На главную Назад
Добро пожаловать, уважаемый посетитель!

 

ГЛАВА 10

Формы

Получение иобработка данных, введенных пользователем,стали неотъемлемой частью большинствауспешных web-сайтов. Бесспорно, возможностинакопления статистики, проведения опросов,хранения персональных настроек и поискавыводят Web на принципиально новый уровень -без них эта среда обладала бы минимальнойинтерактивностью.

Вводинформации в основном реализуется сприменением форм HTML. Несомненно, вы хорошознакомы с принципами работы форм HTML. Какправило, пользователь заполняет в формеодно или несколько полей (например, имя иадрес электронной почты), нажимает кнопкуотправки данных, после чего получаетответное сообщение.

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

Общиесведения о формах

При вводеданных в форму используются различныеуправляющие элементы. В одних элементахпользователь вводит информацию склавиатуры, в других он выбирает нужныйвариант, щелкая кнопкой мыши. В формах могутприсутствовать скрытые поля, которыеподдерживаются самой формой; содержимоескрытых полей не должно изменятьсяпользователем.

Однастраница может содержать несколько форм,поэтому необходимы средства, которыепозволяли бы отличить одну форму от другой.Более того, вы должны как-то сообщить форме,куда следует перейти, когда пользовательвыполняет действие с формой (как правило,нажимает кнопку отправки данных). Обезадачи решаются заключением форм вследующие теги HTML:

<form action = действиеmethod= "метод" -элементы формы -</form>

Как видноиз приведенного фрагмента, в тегах формуказываются два важных элемента: действие иметод. Действие указывает,какой сценарий должен обрабатывать форму, аметод определяетспособ передачи данных этому сценарию.Существует два метода:

  • Метод getпередает все данные формы в конце URL. Из-заразличных ограничений, связанных соспецификой языков и длиной данных, этотметод применяется редко.
  • Метод postпередает все данные формы в теле запроса.Этот метод используется чаще, чем get.

Вэтой главе приведена лишь очень краткаявводная информация по основному син-таксисуформ HTML. Более полную информацию можнонайти в книге А. Хоумера и К. Улмена (СПб.: Питер, 1999).

Элементыформ, ориентированные на ввод с клавиатуры

Нашезнакомство с построением форм начнется сэлементов, ориентированных на ввод склавиатуры. Таких элементов всего два -текстовое поле (text box) и текстовая область (textarea).

Текстовоеполе

В текстовыхполях обычно вводится короткая текстоваяинформация - скажем, адрес электроннойпочты, почтовый адрес или имя. Синтаксисопределения текстового поля:

<input type="text"nате="имя_переменной" size="N"maxlength="N" value="">

Определениетекстового поля включает пять атрибутов:

  • type - типэлемента (для текстовых полей - text);
  • name - имяпеременной, в которой сохраняютсявведенные данные;
  • size - общийразмер текстового поля в браузере;
  • maxlength -максимальное количество символов, вводимыхв текстовом поле;
  • value -значение, отображаемое в текстовом поле поумолчанию.

Текстовоеполе изображено на рис. 10.1.

Рис. 10.1. Текстовоеполе

Особойразновидностью текстовых полей являетсяполе для ввода паролей. Оно работает точнотак же, как обычное текстовое поле, однаковводимые символы заменяются звездочками.Чтобы создать в форме поле для вводапаролей, достаточно указать type="password"вместо type="text".

Текстоваяобласть

Текстоваяобласть (text area) используется для вводанесколько больших объемов текста, неограничивающихся простым именем илиадресом электронной почты. Синтаксисопределения текстовой области:

<textarea name="имя_переменной"rows="N" cols="N" value=""></textarea>

Определениетекстового поля включает три атрибута:

  • name - имяпеременной, в которой сохраняютсявведенные данные;
  • rows -количество строк в текстовой области;
  • cols -количество столбцов в текстовой области.

Текстоваяобласть изображена на рис. 10.2.

 

Рис. 10.2. Текстоваяобласть

Элементыформ, ориентированные на ввод с мыши

В другихэлементах форм пользователь выбирает одиниз заранее определенных вариантов припомощи мыши. Я ограничусь описанием флажков,переключателей и раскрывающихся списков.

Флажок

Флажки (checkboxes)используются в ситуациях, когдапользователь выбирает один или нескольковариантов из готового набора - по аналогиис тем, как ставятся <галочки> в анкетах.Синтаксис определения флажка:

<input type="checkbox"name="имя_переменной"valuе="начальное_значение">

Определениефлажка включает три атрибута:

  • type - типэлемента (для флажков - checkbox);
  • name - имяпеременной, в которой сохраняютсявведенные данные (в данном случае -состояние элемента);
  • value -значение, присваиваемое переменной поумолчанию. Если флажок установлен, именноэто значение будет присвоено переменной суказанным именем. Если флажок не установлен,значение атрибута value не используется.

Флажокизображен на рис. 10.3.

Рис. 10.3. Флажок

Переключатель

Переключатель(radio button) представляет собой разновидностьфлажка; он работает практически так же заодним исключением - в любой момент временив группе может быть установлен лишь одинпереключатель. Синтаксис определенияпереключателя:

<input type="radio"name="имя_переменной" value="начальное_значение">

Как видите,синтаксис почти не отличается отопределения флажка. Определениепереключателя поля включает три атрибута:

  • type - типэлемента (для переключателей - radio);
  • name - имяпеременной, в которой сохраняютсявведенные данные (в данном случае -состояние элемента);
  • value -значение, присваиваемое переменной поумолчанию. Если переключатель установлен,именно это значение будет присвоенопеременной с указанным именем. Если флажокне установлен, значение атрибута value неиспользуется.

Переключательизображен на рис. 10.4.

Рис. 10.4. Переключатель

Раскрывающийсясписок

Раскрывающиесясписки особенно удобны в ситуации, когда увас имеется длинный перечень допустимыхвариантов, из которого пользователь долженвыбрать один вариант. Как правило,раскрывающиеся списки применяются приработе с относительно большими наборамиданных - например, при перечисленииамериканских штатов или стран. Синтаксисопределения раскрывающегося списка:

<select name="имя_переменной">

<option valuе="имя_переменной1">

<option value="имя_переменной2">

<option value="имя_переменнойЗ">

<option value="имя_переменнойN">

</select>

Определениепереключателя поля включает три атрибута:

  • name - имяпеременной, в которой сохраняютсявведенные данные (в данном случае - строка,выбранная в списке);
  • value -значение, отображаемое в списке поумолчанию.

Раскрывающийсясписок изображен на рис. 10.5.

 

Рис. 10.5. Раскрывающийсясписок

Скрытые поля

Скрытые поляне отображаются в браузере и обычноиспользуются для передачи данных междусценариями. Хотя передача в скрытых поляхработает вполне нормально, в РНР существуетдругое, более удобное средство - сеансовыепеременные (см. главу 13). Впрочем, скрытыеполя также используются в некоторыхситуациях и потому заслуживают упоминания.

Синтаксисопределения скрытого поля практическиидентичен синтаксису текстовых полей,отличается только атрибут типа. Посколькускрытые поля не отображаются в браузере,привести пример на страницах книгиневозможно. Синтаксис определения скрытогополя:

<input type="hidden"name="имя_переменной" value="начальное_значение">

Определениескрытого поля включает три атрибута:

  • type - типэлемента (для скрытых полей - hidden);
  • name - имяпеременной, в которой сохраняются скрытыеданные;
  • value -значение, по умолчанию сохраняемое вскрытом поле.

Вообщеговоря, название этого элемента - скрытоеполе - несколько неточно. Хотя скрытые поляне отображаются в браузерах, пользовательможет просто выполнить команду View Source иувидеть, какие скрытые значения хранятся вформе.

Кнопкаотправки данных

Кнопкаотправки данных инициирует действие,заданное атрибутом action тега <form>.Синтаксис определения:

<input type="submit"value="текст_на_кнопке">

Определениекнопки включает два атрибута:

  • type - типэлемента (для кнопки отправки данных - submit);
  • value - текст,по умолчанию отображаемый на кнопке.

Рис. 10.6. Кнопкаотправки данных

Кнопкасброса

Кнопкасброса отменяет все изменения, внесенные вэлементы формы. Обычно никто ею непользуется, однако кнопки сброса так частовстречаются на формах в Web, что я решилпривести ее описание. Синтаксисопределения:

<input type="reset"value=" текст_на_кнопке">

Определениекнопки включает два атрибута:

  • type - типэлемента (для кнопки сброса - reset);
  • value - текст,по умолчанию отображаемый на кнопке.

Кнопкасброса выглядит точно так же, как и кнопкаотправки данных, если не считать того, чтона ней обычно выводится слово (рис. 10.6).

ДжейкобНильсен (Jakob Nielsen), известный авторитет вобласти Web, недавно напи-сал интереснуюстатью о проблемах, связанных сиспользованием кнопки сброса. Статьяопубликована по адресу http://www.useit.com/alertbox/20000416.html.

Все вместе:пример формы

От описаниябазовых компонентов форм мы переходим кпрактическому примеру - построению формыдля обработки данных, введенныхпользователем. Допустим, вы хотите создатьформу, в которой пользователь можетвысказать мнение о вашем Сайте. Примертакой формы приведен в листинге 10.1.

Листинг10.1. Примерформы для сбора данных

<form action ="process.php" method = "post">

<b>Please take amoment to tell us what you think about our site:</b><p>

<b>Name:</b><br>

<input type="text"name="name" size="15" maxlength="25" value=""><br>

<b>Email:</b><br>

<input type="text"name="email" size="15" maxlength="45" value=""><br>

<b>How frequentlydo you visit our site?:</b><br>

<select name="frequency">

<option value="">Sitefrequency:

<option value="0">Thisis my first time

<option value="l">&lt;1 time a month

<option value="2">Roughlyonce a month

<option value="3">Severaltimes a week

<option value="4">Everyday

<optionva1ue-"5">I'm addicted

</select><br>

<b>I frequentlypurchase the following products from our site:</b><br>

<input type="checkbox"name="software" value="software">Software<br>

<input type="checkbox"name="cookware" value="cookware">Cookware<br>

<input type="checkbox"name="hats" value="hats">Chef's Hats<br>

<b>0ur site'sgreatest asset is:</b><br>

<input type="radio"name="asset" value="products">Product selection<br>

<input type="radio"name="asset" value="design">Cool design<br>

<input type="radio"name="asset" value="service">Customer Service<br>

<b>Comments:</b><br>

<textarea name="comments"rows="3" cols="40"></textarea><br>

<input type="submit"value="Submit!">

</form>

Внешний видформы в браузере изображен на рис. 10.7.

 

Рис. 10.7. Примерформы для ввода данных

Вроде бы всепонятно. Возникает вопрос - как получитьданные, введенные пользователем, и сделатьс ними что-нибудь полезное? Этой темепосвящен следующий раздел, <Формы и РНР>.

Не забывайте:все сказанное ранее - не более чем вводныйкурс. Приведенная информация ни в коемслучае не исчерпывает всех возможностей,предоставляемых различными компонентамиформ. За дополнительной информациейобращайтесь к многочисленным учебникам поработе с формами, опубликованным в Web, атакже книгам по HTML.

Отпредварительного знакомства с формами HTMLмы переходим к самому интересному -применению РНР для обработки данных,введенных пользователем в форме.

Формы и РНР

Обработкаданных в формах имеет много общего собработкой переменных, передаваемых в URL, -эта тема подробно рассматривалась впредыдущей главе.

Вводныепримеры

Следующиепрактические примеры помогут вам быстрееосвоить различные аспекты обработки форм вРНР. В этих примерах продемонстрированыразные подходы к реализации интерактивныхвозможностей на сайте.

Пример 1:передача данных формы из одного сценария вдругой

В первомпримере представлена характерная ситуация- когда пользовательские данные вводятсяна одной странице и отображаются на другой.В листинге 10.2 приведен код формы для вводаимени пользователя и адреса электроннойпочты. Когда пользователь щелкает на кнопкеотправки данных (кнопка Go!), формаобращается к странице, приведенной влистинге 10.3. В свою очередь, листинг 10.3выводит переменные $name и $mail, переданные сзапросом.

Листинг10.2. Простаяформа

<html>

<head>

<title>Listing10-2</title>

</head>

<body bgcolor="#ffffff"text="#000000" link="#cbda74" vlink="#808040"alink="#808040">

<form action="listingl0-3.php"method="post">

<b>Give us someinformation!</b><br>

Your Name:<br>

<input type="text"name="name" size="20" maxlength="20" value=""><br>

Your Email:<br>

<input type="text"name="email" size="20" maxlength="40" value=""><br>

<input type="submit"value="go!">

</form>

</body> </html>

Листинг10.3. Отображениеданных, введенных в листинге 10.1

<html> <head>

<title>Listing10-3</title>

</head>

<body bgcolor="#ffffff"text="#000000" link="#cbda74" vlink="#808040"alink="#808040">

<?

// Вывестиимя и адрес электронной почты.

print "Hi. $name!.Your email address is $email";

?>

</body> </html>

В общихчертах происходит следующее: пользовательзаполняет поля формы и нажимает кнопкуотправки данных. Управление передаетсястранице, приведенной в листинге 10.3, гдепроисходит форматирование и последующееотображение данных. Как видите, все просто.

Существует идругой способ обработки данных форм, прикотором используется всего один сценарий. Кнедостаткам этого способа относятсяувеличение сценария и как следствие -затруднения с редактированием исопровождением. Впрочем, есть и достоинства- уменьшение количества файлов, с которымивам приходится работать. Более того, в этомварианте сокращается избыточный код припроверке ошибок (эта тема рассматриваетсяниже в данной главе). Конечно, в некоторыхситуациях работать с одним сценариемнеудобно, но, по крайней мере, вы должнызнать об этой возможности. В примере 2воспроизводится пример 1, но сиспользованием лишь одного сценария.

Пример 2:альтернативная обработка формы (с однимсценарием)

Обработкаданных формы в одном сценарии реализуетсяотносительно просто. Вы проверяете, были липрисвоены значения переменным формы. Еслизначения присвоены, сценарий обрабатываетих (в нашем примере - просто выводит), а еслинет - отображает форму. Решение о том, былоли задано значение переменной или нет,принимается при помощи функции strcmp( ),описанной в главе 8. Пример реализации формыс одним сценарием приведен в листинге 10.4.Обратите внимание: атрибут action формыссылается на ту же страницу, в которойопределяется сама форма. Условная команда if проверяет состояние переменной скрытогополя с именем $seenform. Если значение $seenform незадано, форма отображается в браузере, аесли задано - значит, форма была заполненапользователем и введенные данныеобрабатываются сценарием (в данном примере- просто выводятся в браузере).

Листинг10.4. Вводданных на форме в одном сценарии

<html>

<head>

<title>Listing10-4</title>

</head>

<body bgcolor="#ffffff"text="#000000" link="#cbda74" vlink="#808040"alink="f808040">

<?

// Всекавычки внутри $form должны экранироваться,

// впротивном случае произойдет ошибка.

$form = "

<form action=\"listing10-4.php\"method=\"post\">

<input type=\"hidden\"name=\"seenform\" value=\"y\">

<b>Give us someinformation!</b><br>

Your Name:<br>

<input type=\"text\"name=\"name\" size=\"20\" maxlength=\"20\" value=\"\"><br>

Your Email:<br>

<input type=\"text\"name=\"email\" size=\"20\" maxlength=\"40\" value=\"\"><br>

<input type=\"submit\"value=\"subscribe!\">

</form>";

// Если формаранее не отображалась, отобразить ее.

// Дляпроверки используется значение скрытойпеременной $seenform.

if ($seenform != "у"):

print "$form";

else :

print "Hi. $name!.Your email address is $email";

endif;

?>

</body>

</html>

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

Теперь,когда вы представляете, как простовыполняются операции с формами, мыпереходим к интересному примеру -автоматической отправке данныхпользователя по заданному адресуэлектронной почты. Эта возможностьреализована в примере 3.

Пример 3:автоматическая отправка данных поэлектронной почте

Вывестипользовательские данные в браузеренесложно, но вряд ли это можно назватьсодержательной обработкойпользовательского ввода. Один из способовобработки информации заключается в ееотправке по электронной почте - например,администратору сайта. Хотя при помощигиперссылки mailto: можно отправить сообщениепрямо из браузера, следует учитывать, чтовнешние приложения электронной почтынастроены не на каждом компьютере.Следовательно, отправка сообщений с web-формыболее надежно гарантирует, что сообщениебудет доставлено адресату.

В следующемразделе, mail( ), создается небольшая форма, вкоторой пользователь вводит информацию икомментарии по поводу сайта. Затем данныеформатируются соответствующим образом ипередаются стандартной функции РНР mail( ). Нопрежде чем переходить к построению формы,необходимо предварительно рассмотретьсинтаксис функции mail( ).

mail ( )

Функция mail( )отправляет сообщение заданному адресату поэлектронной почте. Синтаксис функции mail( ):

boolean mail(string получатель, stringтема, string сообщение [, string доп_заголовки])

В параметретема, как нетрудно предположить, передаетсятема сообщения. Параметр сообщениесодержит текст сообщения, а необязательныйпараметр доп_за головки предназначен длявключения дополнительной информации (например,атрибутов форматирования HTML), пересылаемойс сообщением.

Всистеме UNIX функция mail( ) использует утилитуsendmail. В Windows эта функция работает лишь приналичии установленного почтового сервераили если функция mail( ) связана с работающимсервером SMTP. Эта задача решаетсямодификацией переменной SMTP в файле php.ini.

Если высделали все необходимое и функция mail( )работает в вашей системе, попробуйтевыполнить следующий фрагмент (конечно,адрес youraddress@yourserver.com заменяется вашимнастоящим адресом электронной почты):

$email = "youraddress@yourserver.com";

$subject = "This is the subject";

$message = "This is the message";

$headers = "From: somebody@somesite.com";

mail ($email, $subject,$message, $headers);

Хотя приобширной переписке, конечно, следуетиспользовать специализированные почтовыепрограммы вроде majordomo (http://www.greatcircle.com/majordomo),в простых случаях функции РНР mail( )оказывается вполне достаточно.

Итак, послезнакомства с функцией mail( ) можно применитьее на практике. В листинге 10.5 показано, какполучить информацию от пользователя иотправить ее по адресу, заданномуадминистратором сценария.

Листинг10.5. Пересылкапользовательских данных функцией mail( )

<html>

<head>

<title>Listing10-5</title>

</head>

<body bgcolor="#ffffff"text="#000000" link="#cbda74" vlink="#808040"alink="#808040">

// Всекавычки внутри $form должны экранироваться.

// впротивном случае произойдет ошибка.

$form = "

<form action=\"listing10-5.php\"method=\"post\">

<input type=\"hidden\"name=\"seenform\" value=\"y\">

<b>Send us yourcomments!</b><br>

Your Name:<br>

<input type=\"text\"name=\"name\" size=\"20\" maxlength=\"20\" value=\"\"><br>

Your Email:<br>

<input type=\"text\"name-\"email\" size=\"20\" maxlength=\"40\" value=\"\"><br>

Your Comments:<br>

<textarea name=\"comments\"rows=\"3\" cols=\"30\"></textarea><br>

<input type=\"submit\"value=\"submit!\">

</form>

// Если формаранее не отображалась, отобразить ее.

// Дляпроверки используется значение скрытойпеременной $seenform.

if ($seenform != "у") :

print "$form";else :

// Переменная$recipient определяет получателя данных формы

$recipient = "yourname@youremail.com";

// Темасообщения

$subject = "UserComments ($name)";

//Дополнительные заголовки $headers = "From: $email";

// Отправитьсообщение или выдать сообщение об ошибке

mail($recipient, $subject,$comments, $headers) or die("Could not send email!");

// Вывестисообщение для пользователя

print "Thank you$name for taking a moment to send us your comments!";

endif;

?>

</body>

</html>

Неплохо,правда? Листинг 10.5 работает так же, каклистинг 10.4; сначала мы проверяем,отображалась ли форма ранее. Если этопроисходило, программа вызывает функцию mail() и пользовательские данные отправляются поадресу, определяемому переменной $recipient.Затем в браузере выводитсяблагодарственное сообщение дляпользователя.

Простейшимрасширением этого примера будет отправкаблагодарственного сообщения поэлектронной почте (вторым вызовом mail( )).Следующий пример развивает эту идею -пользователю предлагается на выборнесколько бюллетеней. Выбранные бюллетениотправляются по электронной почте.

Пример 4:отправка запрашиваемой информации поэлектронной почте

В этомпримере в форме создается несколькофлажков, каждый из которых соответствуетотдельному документу с информацией о сайте.Пользователь устанавливает один, два илитри флажка, вводит свой адрес, изапрашиваемые брошюры отправляются ему поэлектронной почте. Обратите внимание наприменение массива при работе с флажками -это упрощает проверку выбранных флажков, атакже улучшает структуру программы.

Информационныесообщения хранятся в отдельных файлах. Внашем примере используются три текстовыхфайла:

  • site.txt -информация о сайте;
  • team.txt -информация о талантливых разработчикахсайта;
  • events.txt -приглашение на очередное мероприятие.

Исходныйтекст примера приведен в листинге 10.6.

Листинг10.6.Отправкаинформации, запрашиваемой пользователем

<html>

<head>

<title>Listing10-5</title>

</head>

<body bgcolor="#ffffff"text="#000000" link="#cbda74" vlink="#808040"alink="#808040">

<?

$form = "

<form action=\"Listing10-6.php\"method=\"post\">

<input type=\"hidden\"name=\"seenform\" value=\"y\">

<b>Receiveinformation about our site!</b><br>

Your Email:<br>

<input type=\"text\"name=\"email\" size=\"20\" maxlength=\"40\" value=\"\"><br>

<input type=\"checkbox\"name=\"information[site]\" value=\"y\">Site Architecture<br>

<input type=\"checkbox\"name=\"information[team]\" value=\"y\">Development Team<br>

<input type=\"checkbox\"name=\"information[events]\" value=\"y\">Upcoming Events<br>

<input type=\"submit\"value=\"send it to me!\">

</form>":

if ($seenform != "y"):

print "$form";else :

$headers = "From:devteam@yoursite.com";

// Перебратьвсе пары "ключ/значение"

while ( list($key, Sval)= each ($information) ) :

// Сравнитьтекущее значение с "у" if ($val == "у") :

// Построитьимя файла, соответствующее текущему ключу

$filename = "$key.txt":

$subject = "Requested$key information";

// Открытьфайл

$fd = fopen ($filename,"r");

// Прочитатьсодержимое всего файла в переменную $contents =fread ($fd. filesize ($filename));

// Отправитьсообщение

mail($email, $subject,$contents, $headers) or die("Can't send email!");; fclose($fd);

endif;

endwhile;

// Известитьпользователя об успешной отправке

print sizeof($information)."informational newsletters

have been sent to$email!";

endif;

?>

</body>

</html>

Влистинге 10.6 мы перебираем пары <ключ/значение>в цикле while и отправляем только те бюллетени,у которых значение равно у. Следует помнить,что имена текстовых файлов должнысоответствовать ключаммассива

(site.txt, team.txt иevents.txt). Имя файла строится динамически поключу, после чего файл открывается по имении его содержимое загружается в переменную ($contents).Затем переменная $contents передается функцииmail( ) в качестве параметра.

В следующемпримере пользовательские данныесохраняются в текстовом файле.

Пример 5:сохранение пользовательских данных втекстовом файле

Пользовательскиеданные сохраняются в текстовом файле дляпоследующего статистического анализа,поиска и т. д. - короче, любой обработки повашему усмотрению. В листинге 10.7, как и впредыдущих примерах, данные формыобрабатываются в одном сценарии.Пользователю предлагается ввести четыреобъекта данных: имя, адрес электроннойпочты, язык и профессию. Введеннаяинформация сохраняется в текстовом файлеuser_information.txt. Элементы данных разделяютсясимволами <вертикальная черта> (|).

Листинг10.7. Сохранениепользовательской информации в текстовомфайле

<html>

<head>

<titlexisting10-7</title>

</head>

<body bgcolor="#ffffff"text="#000000" link="#cbda74" vlink="#808040"alink="#808040">

<?

// Создатьформу

$form = "

<form action=\"Listing10-7.php\"method=\"post\">

<input type=\"hidden\"name=\"seenform\" value=\"y\">

<b>Give us yourpersonal info!</fb><br>

Your Name:<br>

<input type=\"text\"name=\"name\" size=\"20\" maxlength=\"20\" value=\"\"><br>

Your Email:<br>

<input type=\"text\"name"=\"email\" size=\"20\" maxlength=\"20\"value=\"\"><br>

Your Preferred Language:<br>

<select name=\"language\">

<option value=\"\">Choosea language:

<option value=\"English\">English

<option value=\"Spanish\">Spanish

<option value=\"Italian\">Italian

<option value=\"French\">French

<option value=\"Japanese\">Japanese

<option value=\"newyork\">NewYork-ese

</select><br>

YourOccupation:'"ibr>

<select name=\"job\">

<option value=\"\">Whatdo you do?:

<option value=\"student\">Student

<option value=\"programmed ">Programmer

<option value=\"manager\">ProjectManager

<option value=\"slacker\">Slacker

<option value=\"chef\">GourmetChef

</select><br>

<input type=\"submit\"value=\"submit!\">

</form>";

//Заполнялась ли форма ранее? if ($seenform != "у"):

print "$form";else :

$fd = fopen("useMnformation.txt","a");

// Убедиться,что во введенных данных не встречается

//вертикальная черта.

$name = str_replace("|","", $name);

$email = str_replace("|","", $email);

// Построитьстроку с пользовательскими данными

$user_row = $name."".$email."|".$language." ".$job."\n";

fwrite($fd, $user_row)or die("Could not write to file!");

fclose($fd);

print "Thank youfor taking a moment to fill out our brief questionnaire!":

endif;

?>

</body>

</html>

Обратитевнимание на фрагмент, в котором мыпроверяем, что пользователь не включил вимя или адрес электронной почты символы <вертикальнаячерта> (|). Функция str_replace( ) удаляет этисимволы, заменяя их пустой строкой. Если быэто не было сделано, пользовательскиесимволы | нарушили бы структуру файладанных и существенно затруднили (а то исделали невозможным) его правильнуюобработку.

При работе сотносительно малыми объемами информациивполне можно обойтись текстовыми файлами.Однако при большом количествепользователей или объеме сохраняемойинформации для хранения и обработки данных,введенных в форме, лучше воспользоватьсябазой данных. Эта тема подробнорассматривается в главе 11.

Донастоящего момента предполагалось, чтопользователь всегда вводит правильныеданные и не действует злонамеренно. Ввысшей степени оптимистичноепредположение! В следующем разделе мыусовершенствуем рассмотренные примеры иорганизуем проверку целостности данныхформ. Проверка ошибок не толькообеспечивает удаление неполной инеправильной информации, но и обеспечиваетболее эффективный и удобный интерфейс.

Проверкаошибок

Обработкапользовательских данных дает осмысленныйрезультат лишь в том случае, если данныеимеют правильную структуру. Проверитьдостоверность введенных данных невозможно,однако вы можете проверить их целостность (например,убедиться в том, что адрес электроннойпочты соответствует стандартному шаблону).Хотя для проверки данных часто применяетсятехнология JavaScript, могут возникнутьпроблемы с несовместимостью браузеров.Поскольку код РНР выполняется на сторонесервера, вы всегда можете быть уверены в том,что проверка данных формы даст нужныйрезультат (конечно, при условииправильности вашей программы).

Приобнаружении ошибки в данных необходимосообщить об этом пользователю и предложитьвнести исправления. Существует нескольковозможных решений, в том числе простойвывод сообщения об ошибке и предложениеальтернативных вариантов (например, еслипользователь выбирает имя, которое уже быловыбрано другим пользователем). В этомразделе рассматривается процедурапроверки и вывода сообщений,

Пример 6:вывод информации о пустых или ошибочнозаполненных полях формы

Ни одинразработчик сайта не захочет раздражатьпользователя невразумительнымисообщениями об ошибках в данных - особенноесли пользователь запрашиваетдополнительную информацию о товаре илиоформляет покупку! Чтобы пользовательпонял, какие поля формы остались пустымиили были заполнены неверно, сообщениядолжны быть четкими и конкретными.

Мыпоследовательно проверяем все поля формы иубеждаемся в том, что они не осталисьпустыми. Там, где это возможно, проверяетсяправильность структуры введенных данных.Если проверка прошла успешно, мы переходимк следующему полю; в противном случаепрограмма выводит сообщение об ошибке,устанавливает флаг, который позднееиспользуется для повторного отображенияформы, и переходит к следующему полю.Процедура повторяется до тех пор, пока небудут проверены все поля формы (листинг 10.8).

Листинг10.8. Проверкаданных формы и вывод сообщений об ошибках

<html>

<head>

<title>Listing10-8</title>

</head>

<body bgcolor="#ffffff"text="#000000" link="#cbda74" vlink="#808040"alink="#808040">

<?

// Создатьформу

$form = "

<form action=\"Listing10-8.php\"method=\"post\">

<input type=\"hidden\"name=\"seenform\" value=\"y\">

<b>Give us someinformation!</b><br>

Your Name:<br>

<input type=\"text\"name=\"name\" size=\"20\" maxlength=\"20\" value=\"$name\"><br>

Your Email:<br>

<input type=\"text\"name=\"email\" s1ze=\"20\" maxlength=\"40\" value=\"$email\"><br>

<inputtype=\"submit\" value=\"subscribe!\">

</form>":

//Заполнялась ли форма ранее?

if ($seenform != "у"):

print "$form";

//Пользователь заполнил форму. Проверитьвведенные данные, else :

$error_flag ="n";

// Убедитьсяв том. что поле имени содержит информацию

if ($name =="") :

print "<fontcolor=\"red\">* You forgot to enter your name!

</font><br>":

$error_flag = "y";

endif:

// Убедитьсяв том. что поле адреса содержит информацию

if ($email =="") :

else :

print "<fontcolor=\"red\">* You forgot to enter your email !

</font><br>"

$error_flag = "y";

//Преобразовать все алфавитные символы вадресе

// электронной почты к нижнемурегистру

$email = strtolower(trim($email)):

// Убедиться вправильности синтаксиса

// адресаэлектронной почты

if (! @eregi('^[0-9a-z]+'.

'([0-9a-z-]+\.)+'.

'([0-9a-z]){2.4}$'. $email)) :

print "<fontcolor=\"red\">* You entered an invalid email address!

</font><br>" :

$error_flag = "y";

endif;

endif;

// Если флагошибки $error_flag установлен.

// зановоотобразить форму

if ($error_flag =="у") : print "$form";

else :

// Обработатьданные пользователя

print "You enteredvalid form information!";

endif;

endif;

?>

</body>

</html>

Программав листинге 10.8 убеждается в том, что поляимени и адреса электронной почты неостались пустыми, а также проверяетправильность синтаксиса вве-, денногоадреса. Если в результате каких-либопроверок в форме обнаруживаются ошибки,программа выводит соответствующиесообщения и отображаетформу заново - при этом вся введенная ранееинформация остается вформе, благодаря чему пользователю будетпроще внести исправления. Если вывестипустую форму и предложить пользователюзаполнить ее заново, он может отправиться

занеобходимым товаром или услугой в другоеместо.

Динамическоеконструирование форм

Донастоящего момента я программировал всеформы вручную. Любому программистуизвестно, что ручное кодирование - этоплохо, поскольку оно увеличиваетвероятность ошибок, не говоря уже о лишнихзатратах времени.

В следующемразделе я представлю сценарий, в которомраскрывающийся список строитсядинамически по содержимому массива. Этотприем несложен, однако

он экономитнемало времени как при исходномпрограммировании, так и при последующемсопровождении программы.

Пример 7:построение раскрывающегося списка

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

В листинге10.9, как и в предыдущих примерах, реализованвариант с одним сценарием. Сначала мыпроверяем, было ли присвоено значениепеременной $site. Если проверка даетположительный результат, вызываетсяфункция header( ) с параметром, в которомзначение $site присоединяется к строке .При передаче этой команды функция header Оперенаправляет браузер на указанный URL.Если значение переменной $site не задано,форма выводится в браузере. Раскрывающийсясписок строится в цикле, количествоитераций зависит от размера массива Sfavsites. Влистинге 10.9 я включил в этот массив пятьсвоих любимых сайтов. Конечно, вы можетедобавить в него сколько угодно своих сайтов.

Запомнитеодно важное обстоятельство - функция header( )должна вызываться до вывода данных вбраузере. Ее нельзя просто вызвать в любойточке сценария РНР. Несвоевременные вызовыheader( ) порождают столько проблем у неопытныхпрограммистов РНР, что я рекомендуюповторить это правило раз пять, чтобы лучшезапомнить его.

Листинг10.9. Динамическоепостроение раскрывающегося списка

<?

if ($site !="") :

header("Location:http://Ssite");

exit;

else :

?>

<html>

<head>

<title>Listing10-9</Fit1e>

</head>

<bodybgcolor="#ffffff" text="#000000" Iink="#cbda74"vlink="#808040" alink="#808040"

$favsites = array("www.k10k.com". "www.yahoo.com",

"www.drudgereport.com",

"www.phprecipes.com",

"www.frogdesign.com"):

// Создатьформу

<?

<form action ="Listing10-9.php" method="post">

<selectname="site">

<option value ="">Choose a site:

$х = 0:

while ( $х < sizeof($favsites) ) :

print "<optionvalue='$favsites[$x]'>$favsites[$x]";

$x++;

endwhile;

?>

</select>

<inputtype="submit" value="go!">

</form>

<?

endif;

?>

Динамическоеконструирование форм особенно удобно приобработке больших объемов данных, которые влюбой момент могут измениться, что приведетк устареванию всей жестко закодированнойинформации форм. Впрочем, я рекомендуюжестко кодировать все статические данные (например,список штатов США), поскольку это ускоритработу программы.

Проект:гостевая книга

С первыхдней World Wide Web разработчики сайтовстремились к тому, чтобы посетители моглиподелиться своими мыслями и комментариямипо поводу сайта. На сайтах эта возможностьобычно называется <гостевой книгой> (guestbook).Я покажу, как легко создать гостевую книгупри помощи форм HTML, средств обработки формРНР и текстового файла.

Прежде всегосоздается инициализационный файл,содержащий некоторые глобальныепеременные и функции приложения (листинг10.10).

Листинг10.10. Файлinit.inc, используемый при создании гостевойкниги

<?

// Файл: init.inc

// Назначение:глобальные переменные и функции дляпроекта гостевой книги

// Заголовокстраницы по умолчанию

$title = "My Guestbook";

// Цвет фона

$bg_color ="white": /

// Гарнитурашрифта

$font_face ="Arial, Verdana, Times New Roman";

// Цветшрифта

$font_color ="black";

// Датаотправки $post_date - date("M d y");

// Файлданных гостевой книги

$guest_file ="comments.txt";

// Функциячитает данные гостевой книги

//и отображаетих в браузере

function view_guest($guest_file) {

GLOBAL $font_face,$font_color;

print "Return to<ahref=\"index.php\">index</a>,<br><br>";

// Если вфайле гостевой книги имеются данные...

if(filesize($guest_file) > 0) :

// Открытьфайл данных гостевой книги

$fh =fopen($guest_file. "r") or die("Couldn't open $guest_file");

print "<tableborder=1 cellpadding=2 cellspacing=0 width=\"600\">";

// Повторятьдо конца файла

while (! feof($fh)) :

// Прочитатьследующую строку

$line <= fgetsdfh, 4096);

// Разбитьстроку на компоненты

// иприсвоить каждый компонент переменной

list($date. $name,$email, $comments) = explode("|", $line):

// Еслиуказано имя посетителя, вывести его

if ($name !="") :

print"<tr>":

print"<td><font color=\"$font_co!or\"

face=\"$font_face\">Date:</font></td>";

print"<td><font color=\"$font_color\"

face=\"$font_face\">$date</font></td>";

print"</tr>";

print"<tr>";

print"<td><font color=\"$font_color\"

 face=\"$font_face\">Name:</font></td>";

print"<td><font color=\"$font_color\"

 face=\"$font_face\">$name</font></td>";

print"</tr>";

print"<tr>";

print"<td><font color=\"$font_color\"

 face=\"$font_face\">Email:</font></td>";

print"<td><font color=\"$font_color\"

 face=\"$font_face\">$email</font></td>";

print"</tr>";

print"<tr>";

print "<tdvalign=\'top\"><font color=\"$font_color\"

face=\"$font_face\">Message:</font></td>";

print"<td><font color=\"$font_color\"

face=\"$font_face\">$comments</font></td>";

print "</tr>";

print"<tr><tdcolspan=\"2\">&nbsp:</td></tr>";

endif;

endwhile;

print"</table>";

// Закрытьфайл

fclose($fh);

else :

print"<h3>Currently there are no entries in theguestbook!</h3>";

endif;

} // view_guest

// Функциясохраняет новую информацию в файле данных

functionadd_guest($name, $email, $comments) {

GLOBAL $post_date,$guest_file;

//Отформатировать данные для ввода ,

$contents ="$post_date|$name|$email |$comments\n";

// Открытьфайл данных

$fh =fopen($guest_file. "a") or dieC'Could not open $guest_file!");

// Записатьданные в файл

$wr = fwrite($fh,$contents) or die("Could not write to $guest_file!");

// Закрытьфайл fclose($fh);

} // add_guest

?>

Затемсоздаются еще три файла: файл ссылок index.php,файл add_guest.php для вывода информации гостевойкниги и файл view_guest.php для ввода новых данных.Файл index.php (листинг 10.11) просто отображаетдве ссылки для выполнения основных функцийгостевой книги - просмотра и добавленияновых данных. Эти ссылки легко включаются всайт, имеющий более сложную структуру.

Листинг 10.11.Файл index.php со ссылками для просмотра идобавления новых данных в гостевую книгу

<html>

<?

INCLUDE("init.inc");

?>

<head>

<title><?=$page_title;?></title>

</head>

<bodybgcolor="<?=$bg_color;?>" text="#000000"link="#808040" vlink="#808040" alink="#808040">

<ahref="view_guest.php">View the guestbook!</a><br>

<ahref="add_guest.php">Sign the guestbook!</a><br>

</body>

</html>

Файл view_guest.php(листинг 10.12) выводит всю информациюгостевой книги, хранящуюся в файле данных.

Листинг10.12. Файлview_guest.php

<html>

<?

INCLUDE("init.inc");

?>

<head>

<t1tle><?=$page_title;?></t1tle>

</head>

<bodybgcolor="<?=$bg_color:?>" text="#000000" link="vlink="#808040" alink="#808040">

vi ew_guest ( $guest_file );

?>

Файл add_guest.php(листинг 10.13) запрашивает у пользователяновые данные для внесения в гостевую книгу.Введенная информация записывается в файлданных.

Листинг10.13. Файлadd_guest.php

<html>

<?

INCLUDE("init.inc");

?>

<head>

<title><?=$page_title:?></title>

</head>

<bodybgcolor="#ffffff" text="#000000" link="#808040"vlink="#808040" alink="#808040">

?<

// Если формаеще не отображалась - запросить данные упользователя

if (! $seenform) :

?>

<formaction="add_guest.php" method="post">

<inputtype="hidden" name="seenform" value="y">

Name:<br>

<inputtype="text" name="name" size="15"maxlength="30" value=""><br>

Email:<br>

<inputtype="text" name="email" size="15"maxlength="35" value=""><br>

Comment: <br>

<textareaname="comment" rows="'3"cols="40"></textarea><br>

<inputtype="submit" value="submit">

</form>

// Форма ужеотображалась - добавить данные в текстовыйфайл.

else :

add_guest($name, $email,$comment);

print"<h3>Your comments have been added to the guestbook.

<ahref=\"index.php\">Click here</a> to return to the index.</h3>";

endif;

?>

К числуосновных преимуществ модульной разработкиприложений относится простота адаптациидля других систем. Допустим, вы решилиперейти от хранения данных в текстовомфайле к использованию базы данных. Стоитизменить содержимое add_guest( ) и view_guest( ), и вашагостевая книга перейдет на работу с базойданных.

На рис. 10.8показано, как выглядит гостевая книга послесохранения пары записей.

 

Рис. 10.8. Просмотргостевой книги (view_guest.php)

Информация,показанная на рис. 10.8, хранится в файледанных в следующем виде:

Oct 2900|Michele|michelle@latorre.com|I love cheese!

Oct 29 00|Nino|nino@latorre.com|Greatsite!

Итоги

Обработкаданных форм принадлежит к числу сильнейшихсторон РНР, поскольку простота и надежностьсочетаются в ней с одним из важнейшихаспектов любого сайта - интерактивностью.В этой главе рассматривался широкий кругвопросов, относящихся к формам и роли РНР вобработке данных форм, в том числе:

  • общиесведения о синтаксисе форм;
  • передачаданных форм между сценариями РНР;
  • обработкаформ в одном сценарии;
  • функцияmail();
  • отправкаданных формы по электронной почте;
  • автоматическаяобработка пользовательских запросов наполучение информации;
  • сохранениеданных пользователя в текстовом файле;
  • проверкаошибок;
  • динамическоеконструирование форм.

Если высобираетесь работать со сколько-нибудьзаметными объемами информации, одним изпервых шагов на этом пути должна статьинтеграция базы данных в структуру сайта.Эта тема рассматривается в следующей главе.