Изучаем PHP: Часть 1. Страница регистрации, формы и взаимодействие с базой данных Уровень сложности: средний Николас Чейз, автор, Studio B Тайлер Андерсон, Независимый автор, Stexar Corp. 12.01.2007 Из этого учебного пособия, первого из трех в серии "Изучаем PHP", вы узнаете, как использовать PHP для создания простейшего приложения, поддерживающего workflow. Вы научитесь строить PHP-страницы с использованием HTML-форм и получать доступ к базам данных. Опц Прежде чем начать Об этом учебном пособии Цель этого учебного пособия -- научить вас писать на языке PHP приложения, поддерживающие workflow. Мы начнем с того, что научимся регистрироваться с определенным именем пользователя и паролем, загружать файлы на сервер из браузера, просматривать загруженные файлы. В дальнейшем для пользователей с административными полномочиями мы разработаем специальную процедуру одобрения документов для публичного доступа. В последующих двух частях этой серии (Часть 2 и Часть 3) мы рассмотрим HTTPаутентификацию, использование потоков данных, обработку исключений и другие важные вопросы. В этом пособии рассматриваются следующие темы: Выс учеб Создание базовой страницы Переменные, циклы и условные операторы if-then Массивы и функции Доступ к базам данных Включение файлов с помощью оператора include Для кого написано это пособие? Если вам раньше не приходилось сталкиваться с PHP, но вы хотите научиться писать Web-ориентированные приложения, то начните изучение с д является первой частью в серии из трех учебных пособий. PHP является языком скриптового типа, он очень прост в изучении, но с его помощью м сложные приложения с широкой функциональностью. Это учебное пособие научит вас писать несложные приложения, строить PHP-страницы с ис получать доступ к базам данных. Требования к подготовке В этом учебном пособии предполагается, что у вас нет никакого опыта работы с PHP. Знакомство с концепциями и форматом HTML может быть пол опыта программирования не требуется. Инструментальные средства Вам необходимо иметь Web-сервер, PHP и базу данных. Если у вас есть доступ к сети, в которой установлен сервер PHP V5 с доступом к базе данн воспользоваться. В противном случае загрузите и установите следующие пакеты: Web-сервер Вне зависимости от того, работаете ли вы под Windows, Linux или Mac OS X, вы имеете возможность использовать Apache Web-сервер. В версиями Apache V1.3 или 2.0, но примеры в этом пособии ориентированы на версию V2.0. Если вы работаете под Windows, вы можете Internet Information Services, встроенный в Windows Web-сервер. PHP V5 Вам необходим дистрибутив PHP. Во время написания этого пособия в ходу были версии PHP V4 и V5, в своих примерах мы ориентирова версиях PHP несущественны для этой части пособия, но в двух последующих частях они станут заметны. MySQL Одной из тем этого учебника является получение доступа к базе данных. Соответственно, вам нужна та или иная база данных. Мы разб MySQL, поскольку именно эта база данных как правило используется вместе с PHP. Изучаем PHP: Часть 1. Страница регистрации, формы и взаимодействие с базой данных Базовый синтаксис PHP Страница 2 из 10 Простая PHP-страница Для начала давайте создадим PHP-страницу самыми простыми средствами. В следующем разделе мы рассмотрим использование HTML-форм с PHP для ввода данных, но прежде хотим познакомить вас с базовыми средствами решения основных задач. Начните с создания простой PHP-страницы: <html> <title>Workflow Registration</title> <body> <p>You entered:</p> <p><?php echo "Some Data"; ?></p> </body> </html> Опции документа Распечатать эту страницу Обсудить Выскажите мнение об этом учебном пособии Помогите нам улучшить содержание В этом примере мы видим простую HTML-страницу c одной PHP-секцией, которая выделена жирным шрифтом. Когда Web-сервер встречает последовательность символов <?php, то это служит для него сигналом, что далее следуют команды, а не просто текст, который надо послать браузеру. Сервер продолжает выполнять команды PHP, каким образом -- мы обсудим чуть ниже, до тех пор, пока не дойдет до признака конца секции, а именно символов ?>. В нашем случае есть только одна команда, echo, это инструкция серверу вывести текст, который стоит после нее в кавычках. То есть, если вы сохраните эту страницу и захотите просмотреть ее своим браузером, браузер получит следующий текст: <html> <title>Workflow Registration</title> <body> <p>You entered:</p> <p>Some Data</p> </body> </html> Чтобы посмотреть, как это работает, сохраните текст PHP-страницы в файл с именем registration_action.php и поместите файл в корневую папку с документами для вашего сервера. Для Apache это будет папка, похожая на /var/www/html, для Internet Information Services это будет папка, похожая на C:\Inetpub\wwwroot. Откройте браузер с адресом http://localhost/registration_action.php. Результат работы вашего браузера будет подобен тому, что вы можете видеть ниже на Рисунке 1. Рисунок 1. Результат работы команды echo XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. Таким образом, вы написали свою первую страницу с использованием PHP. В начало Переменные Переменная служит контейнером и именем для данных. С того момента, как вы присвоили переменной некоторое значение, PHP всегда, встретив эту переменную, заменит ее на приписанное значение. Рассмотрим пример, для этого внесите следующие изменения в свою страницу: <html> <title>Workflow Registration</title> <body> <p>You entered:</p> <?php $username = "tyler"; $password = "mypassword"; echo "<p>Username = " . $username . "</p>"; echo "<p>Password = " . $password . "</p>"; ?> </body> </html> Сохраните файл и обновите страницу вашего браузера. То, что вы увидите, будет похоже на Рисунок 2. Рисунок 2. Страница браузера после обновления XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. Обратите внимание на то, что каждая строка заканчивается точкой с запятой. Для объединения или конкатенации двух текстовых элементов используется точка. Вы можете объединить таким образом любое число строк или текстовых элементов. Еще одно замечание: имена переменных в PHP чувствительны к регистру, то есть, $UserName и $username -- это две совершенно различные переменные. Поскольку ошибки подобного рода довольно сложно отыскивать, в PHP существует ряд соглашений о правилах наименования переменных. Одно из этих правил гласит, что имена переменных должны состоять из символов в нижнем регистре. Прежде чем двинуться дальше, рассмотрим специальный тип переменных. В начало Константы Вы можете свободно изменять значение переменной, но иногда бывает полезно задать переменную, значение которое не может быть изменено. Такие объекты называются константами. Например, вы можете определить константу для хранения заголовка, который будет выводиться на каждой странице: <?php define("PAGE_TITLE", "Workflow Registration"); ?> <html> <title><?php echo PAGE_TITLE ?></title> <body> <p>You entered:</p> ... (Этот пример может показаться тривиальным, но в дальнейшем вы убедитесь, что такое определение полезно, когда речь идет о нескольких страницах.) Заметьте, что в этом операторе задается пара: имя константы и ее значение. Если вы попытаетесь изменить значение константы после того, как оно было определено, то получите сообщение об ошибке. Заметьте также, что при ссылке на константу в элементе title мы не использовали знак доллара, как это делается перед именами переменных. Вы можете присваивать константам произвольные имена, но, согласно принятым правилам, имена констант состоят из прописных букв. В начало Упрощенный вывод До сих пор мы использовали команду echo для отображения информации, но это довольно громоздкая конструкция. В тех случаях, когда вывести нужно один элемент, существует более постой способ. Для вывода данных в PHP существует оператор вывода, вы можете передать данные при помощи конструкции <?= ?> : <?php define("PAGE_TITLE", "Workflow Registration"); ?> <html> <title><?= PAGE_TITLE ?></title> <body> <p>You entered:</p> ... Обратите внимание, что за оператором вывода не следует точка с запятой. В дальнейшем вы познакомитесь с другими базовыми конструкциями PHP, такими как условный оператор if-then, которые необходимы для построения приложений. Изучаем PHP: Часть 1. Страница регистрации, формы и взаимодействие с базой данных Формы и PHP Страница 3 из 10 Создание и использование форм в PHP Язык PHP изначально разрабатывался как язык для Web-программирования. Конечно, вы можете запустить PHP из командной строки, но фактически случаи использования PHP вне Webприложений очень редки. Как правило PHP используется вместе с HTML-формами. Вы создаете форму с использованием HTML, затем пользователь вводит данные в эту форму и инициирует ее передачу, браузер пересылает данные серверу в форме массива. В этом разделе мы определим, что такое массив данных, рассмотрим способы работы с данными в формах. Вы также познакомитесь с конструкциями, управляющими ходом выполнения PHPскрипта, такими как циклы и условные операторы if-then. Опции документа Распечатать эту страницу Обсудить Выскажите мнение об этом учебном пособии Помогите нам улучшить содержание В начало Создание форм в HTML Начнем с создания страницы регистрации для вашего приложения. На этой странице пользователи будут вводить свои данные, а вы будете утверждать их, то есть выполнять некоторые проверки, прежде чем переслать данные в базу. Для начала просто создадим форму для ввода. Создадим новый файл registration.php и поместим в него следующий текст: <html> <head><title>Workflow System</title></head> <body> <h1>Register for an Account:</h1> <form action="registration_action.php" method="GET"> Username: <input type="text" name="name" /><br /> Email: <input type="text" name="email" /><br /> Password: <input type="password" name="pword" /><br /> <input type="submit" value="GO" /> </form> </body> </html> Таким образом, мы имеем простую форму, которая содержится внутри HTML-тега form, в ней есть текстовое поле для ввода пароля и клавиша для отсылки данных. Сохраните этот текст в файл с именем registration.php и поместите файл в корневую папку с документами для вашего сервера, затем откройте браузер с адресом http://localhost/registration.php. Результат работы вашего браузера будет похож на то, что можно видеть ниже, на Рисунке 3. Рисунок 3. Форма для регистрации XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. Обратите внимание на то, что в поле для ввода пароля не отображаются символы, которые вы набираете, вместо этого появляются звездочки. Что же происходит, когда пользователь нажимает клавишу GO? В начало Передача данных из формы Рассмотрим подробнее формат элемента form нашей формы. <form action="registration_action.php" method="GET"> В этом элементе определено два параметра. Первый, action, сообщает браузеру куда посылать информацию. В нашем случае ссылка ведет к тому файлу, который мы создали ранее, registration_action.php. Второй параметр, method, сообщает браузеру как передавать данные. Посмотрим, как это работает. Введите какие-либо данные и нажмите кнопку GO. Вы увидите нечто похожее на Рисунок 4. Рисунок 4. Вывод данных, введенных в форму XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. В том случае, если вы не ввели данные, но нажали кнопку, форма будет работать также, поскольку у нас пока еще не налажен прием введенных данных. Обратите внимание на URL, который появился в поле адреса браузера. http://localhost/registration_action.php?name=roadnick&email= ibmquestions%40nicholaschase.com&pword=supersecretpassword Заметьте, что каждому элементу формы в URL соответствует пара имя-значение и эти пары разделены амперсандами. Такой вид URL обусловлен тем, что мы использовали в качестве метода передачи GET. Далее мы рассмотрим использование метода POST, но прежде научимся принимать данные из формы в PHP-страницу. В начало Прием данных из формы Рассмотрим, каким образом данные, введенные в HTML-форму, можно сделать доступными в принимающей PHP-странице. Внесите следующие изменения в файл registration_action.php: ... <body> <p>You entered:</p> <?php $username = $_GET['name']; $password = $_GET['pword']; echo "<p>Username = " . $username . "</p>"; echo "<p>Password = " . $password . "</p>"; ?> </body> </html> Значения переменных будут теперь выбираться по имени из массива $_GET. Чуть ниже мы поговорим о массивах подробнее, а сейчас попробуйте обновить окошко браузера, вы увидите, что введенные нами данные появились на своих местах, как показано на Рисунке 5. Рисунок 5. Введенные данные отображаются в браузере XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. Вы можете извлечь любую часть переданной информации по имени, но есть и другие возможности работы с массивами. В начало Массивы В PHP можно организовывать массивы данных, то есть списки значений, это позволяет легко перемещать одновременно целые группы данных. Например, создадим массив из трех элементов и передадим его для вывода на страницу: $formnames = array("name", "email", "pword"); echo "0=".$formnames[0]."<br />"; echo "1=".$formnames[1]."<br />"; echo "2=".$formnames[2]."<br />"; Функция array() возвращает переменную, которая является массивом. (О том, что такое функция, мы будем говорить позже, пока же достаточно понимать, что функцию можно вызвать и что она возвращает значение того или иного типа, которое вы приписываете переменной.) Результат работы этого скрипта будет такой: 0=name<br /> 1=email<br /> 2=pword<br /> Заметьте, что первое значение в массиве имеет индекс, равный 0, но не 1. Заметьте также, что мы выделяем нужное значение, добавив индекс в квадратных скобках к имени массива. Подобным же образом мы получали доступ к значениям переменной формы. Переменная $_GET является именем массива специального типа, ассоциативного массива, к элементам которого обращаются не по индексам, а по ключам. В тот момент, когда вы отсылаете свою форму, вы по существу дела создаете ассоциативный массив: $_GET = array("name" => "roadnick", "email" => "ibmquestions@nicholaschase.com", "pword" => "supersecretpassword"); Именно этот факт позволяет вам впоследствии выделить отдельные значения, например, $_GET["name"], имена переменных в этом случае играют роль ключей. В начало Получение информации о массиве Ассоциативные массивы крайне полезны при передаче данных между формами, но при их использовании может возникнуть трудность, далеко не всегда известна структура массива. Такая ситуация может быть, например, если ассоциативный массив был получен в результате выполнения запроса к базе данных. В PHP есть две функции, которые облегчают использование таких массивов: <body> <p>You entered:</p> <?php $form_names = array_keys($_GET); $form_values = array_values($_GET); echo "<p>" . $form_names[0] . " = " . $form_values[0] . "</p>"; echo "<p>" . $form_names[1] . " = " . $form_values[1] . "</p>"; echo "<p>" . $form_names[2] . " = " . $form_values[2] . "</p>"; ?> </body> </html> Функции array_keys() и array_values() возвращают обыкновенные массивы, к элементам которых можно обращаться при помощи числовых индексов, как показано ниже на Рисунке 6. Рисунок 6. Извлечение данных из массива с использованием числовых индексов XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. Этот способ работы с массивами также имеет неудобства. Например, вы можете не знать, сколько всего элементов в ассоциированном массиве. В PHP существуют и другие способы обращения с ассоциированными массивами. Следующим шагом мы рассмотрим два таких способа. В начало Использование цикла for-next Задача последовательный обработки некоторого числа однотипных значений возникает очень часто. Для ее выполнения применяется такая конструкция как цикл. Вот один из примеров цикла: for ($i = 0; $i < 10; $i++) { echo $i . " "; } Результат его работы будет следующим: 0 1 2 3 4 5 6 7 8 9 Рассмотрим синтаксис выражения for. Первоначально PHP приписывает значение 0 переменной $i. Цикл продолжается до тех пор, пока значение переменной $i остается меньше 10, на каждом шаге цикла значение переменной $i увеличивается на единицу. Поскольку у нас есть возможность узнать, сколько всего значений содержит массив $_GET, мы легко можем организовать цикл, который отобразит все значения, переданные нам из формы: <body> <p>You entered:</p> <?php $form_names = array_keys($_GET); $form_values = array_values($_GET); for ($i = 0; $i < sizeof($_GET); $i++) { echo "<p>".$form_names[$i]." = " . $form_values[$i] . "</p>"; } ?> </body> </html> Функция sizeof() возвращает число элементов массива, в нашем случае массива $_GET. Вы можете использовать возвращаемое этой функцией значение в условном операторе, который останавливает выполнение цикла, результат работы цикла показан ниже на Рисунке 7. Рисунок 7. Использование функции sizeof для остановки цикла XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. Для работы с ассоциированным массивом $_GET вы можете использовать и другой тип цикла, цикл с ключевым словом foreach. В начало Использование цикла foreach Ассоциированные массивы настолько часто используются в PHP, что для работы с ними была создана специальная конструкция, которая позволяет получать доступ к данным, минуя ключи. Вместо этого вы можете использовать цикл foreach, он позволяет манипулировать с данными массива напрямую. Давайте рассмотрим пример кода: ... <?php foreach ($_GET as $value) { echo "<p>" . $value . "</p>"; } ?> На первом шаге цикла будет извлечено первое значение из массива $_GET, это значение будет приписано переменной $value, затем это значение выводится командой echo. Затем цикл повторяется, переменной $value приписывается второе значение и так далее, цикл работает до тех пор, пока в массиве $_GET еще остаются необработанные элементы. Результат работы этого цикла будет следующим: <p>roadnick</p> <p>ibmquestions@nicholaschase.com</p> <p>supersecretpassword</p> Эта конструкция позволяет извлекать не только значения элементов ассоциированного массива, но и ключи: ... <?php foreach ($_GET as $key=>$value) { echo "<p>".$key." = " . $value . "</p>"; } ?< ... Такой вариант кода приведет нас к результату, который мы уже видели выше: Рисунок 8. Исходный вариант вывода XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. В начало Повторяющиеся значения в формах Иногда возникает ситуация, когда в форме должно быть введено несколько значений для переменной с одним и тем же именем. Примером может служить поле пароля pword. Поскольку пользователи не могут видеть символы пароля, которые они набирают, то вы можете попросить их ввести пароль дважды, для того чтобы убедиться, что они не сделали ошибку при вводе: ... Username: <input type="text" name="name" /><br /> Email: <input type="text" name="email" /><br /> Password: <input type="password" name="pword[]" /><br /> Password (again): <input type="password" name="pword[]" /><br /> <input type="submit" value="GO" /> ... Заметьте, что имя поля pword несколько изменилось. Поскольку это поле должно содержать несколько значений, то оно само стало массивом. Таким образом, массив передаваемых данных для этой формы будет содержать в качестве одного из своих элементов другой массив. Когда вы нажмете кнопку отправки формы, то в поле адреса возникнет следующий URL: http://localhost/registration_action.php?name=roadnick&email=ibmquestions%40nicholas chase.com&pword[]=supersecretpassword&pword[]=supersecretpassword При этом в процессе обработки будет создан массив: $passwords = array("supersecretpassword", "supersecretpassword"); $_POST = array("name"=>"roadnick", "email"=>"ibmquestions@nicholaschase.com", "pword"=>$passwords); В этом варианте для просмотра значения пароля вы должны обращаться к соответствующей переменной как к массиву с числовым индексом: ... foreach ($_GET as $key=>$value) { echo "<p>".$key." = " . $value . "</p>"; } $passwords = $_GET["pword"]; echo "First password = ".$passwords[0]; echo "<br />"; echo "Second password = ".$passwords[1]; ... Если вы отошлете форму (не забудьте обновить страницу), то можете заметить некоторые изменения, как показано ниже на Рисунке 9. Рисунок 9. Новый вариант вывода XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. Обратите внимание, в поле, где раньше отображался пароль, появилось слово Array, элементы самого массива отображены ниже. В начало Отличия методов GET и POST До сих пор для передачи данных из формы мы использовали метод GET, главным неудобством и ограничением этого метода является тот факт, что передаваемые данные помещаются прямо в адрес URL. В некоторых случаях это вполне допустимо, в других -- нет. Например, вам требуется передать из формы большой блок данных из поля типа textarea, обычно такой тип используется для размещения комментариев. Как правило, Web-сервер ограничивает число символов, которые можно поместить в URL-адрес, таким образом передать данные посредством метода GET просто невозможно. Согласно принятым стандартам технологии Web-программирования, метод GET не следует использовать для передачи данных в скрипты, которые могут иметь "побочные эффекты", а фактически любой скрипт, в котором происходит обработка данных, обладает этим свойством. До сих пор мы только отображали введенные данные, обработки не происходило, но если мы хотим добавить запись в базу данных, то это уже обработка, которая может иметь побочный эффект. Тот факт, что метод GET передает данные в URL-адресе открытым, то есть, доступным для просмотра образом, не только влияет на безопасность системы, но обладает и другими неудобствами. Например, пользователь может сделать закладку на этот адрес, что приведет к тому, что операция будет выполняться много раз; поисковые машины, которые индексируют URL-адреса, могут перехватить данные, направляемые в вашу базу и так далее. Поэтому в большинстве случаев имеет смысл пользоваться методом POST, который передает данные в теле запроса, а не в заголовке, как метод GET. В начало Использование метода POST Внешне использование метода POST мало отличается от использования метода GET. Сначала внесем изменения в файл registration.php: ... <h1>Register for an Account:</h1> <form action="registration_action.php" method="POST"> Username: <input type="text" name="name" /><br /> ... При отсылке формы вы увидите, что содержание URL-адреса изменилось: http://localhost/registration_action.php Изменения нужны и в файле registration_action.php, для приема данных вместо массива $_GET будет использоваться массив $_POST: ... <body> <p>You entered:</p> <?php foreach ($_POST as $key=>$value) { echo "<p>".$key." = " . $value . "</p>"; } $passwords = $_POST["pword"]; echo "First password = ".$passwords[0]; echo "<br />"; echo "Second password = ".$passwords[1]; ?> </body> </html> Дальнейшая работа с массивом $_POST происходит точно так же, как и с массивом $_GET. В начало Контроль данных: условный оператор if-then Выше мы попросили пользователя ввести пароль дважды. Теперь посмотрим, как можно проверить, не было ли сделано ошибки при вводе пароля. Для этого используем условный оператор if-then: ... $passwords = $_POST["pword"]; echo "First password = ".$passwords[0]; echo "<br />"; echo "Second password = ".$passwords[1]; if ($passwords[0] == $passwords[1]) { echo "<p>Passwords match. Thank you.</p>"; } else { echo "<p>Passwords don't match. Please try again.</p>"; } ... В заголовке условного оператора в скобках помещено некоторое выражение (в нашем примере это $passwords[0] == $passwords[1]), которое может быть истинно (TRUE) или ложно (FALSE). Если оно истинно, то PHP выполняет тот оператор, который следует за условным выражением, это может быть блок операторов в фигурных скобках. Если оно ложно, что выполняется блок, следующий за ключевым словом else, а если его нет, то скрипт переходит к выполнению следующего оператора. Обратите внимание на то, что мы написали $passwords[0] == $passwords[1], а не $passwords[0] = $passwords[1], то есть использовали двойной знак равенства. Это не случайно. Простой знак равенства работает как оператор присваивания, то есть, значение $passwords[0] в этом случае просто станет равным $passwords[1]. Нам же надо совсем не это, мы хотим сравнить значения переменных и поэтому используем оператор сравнения -- двойное равенство. Ниже, на Рисунке 10, показана страница, которую увидит пользователь в том случае, если он сделал ошибку при вводе пароля. Рисунок 10. Предупреждение об ошибке при вводе пароля XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. Для формирования более сложных логических выражений можно применять логические операторы, например, оператор И (&&) и оператор ИЛИ (||). Рассмотрим следующее выражение: if (($today == "Monday") && ($status == "Not a holiday")) { echo "GO TO WORK!!!"; } Значение логического выражения в скобках будет истина (TRUE) в том случае, если сегодня понедельник (Monday) И этот день не является праздничным. Функции Создание функций Когда вы разрабатываете значительную по размеру программу, то в ней, как правило, есть сегменты кода, которые выполняются несколько раз. Кроме того, выделение фрагментов, отвечающих за определенные действия, делает программу более прозрачной, ее будет легче читать и модифицировать. Именно для этих целей и служат функции. Например, вы можете выделить проверку пароля в отдельную функцию: ... <body> <p>You entered:</p> <?php function checkPasswords($firstPass, $secondPass){ if ($firstPass == $secondPass) { echo "<p>Passwords match. Thank you.</p>"; } else { echo "<p>Passwords don't match. \ Please try again.</p>"; } } foreach ($_POST as $key=>$value) { echo "<p>".$key." = " . $value . "</p>"; } $passwords = $_POST["pword"]; echo "First password = ".$passwords[0]; echo "<br />"; echo "Second password = ".$passwords[1]; ?> </body> </html> Когда сервер будет обрабатывать эту страницу и дойдет до ключевого слова function, он пропустит следующий блок, поскольку функции выполняются только по специальному запросу, и перейдет непосредственно в выполнению цикла foreach, как можно видеть ниже на Рисунке 11. Рисунок 11. Выполнение цикла foreach XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. Для того чтобы использовать функцию, ее надо вызвать. В начало Вызов функции Вызов функции состоит из указания ее имени, следом за которым должна идти пара круглых скобок. В том случае, если функция принимает какие-либо параметры, их помещают в скобках через запятую, например: ... <body> <p>You entered:</p> <?php function checkPasswords($firstPass, $secondPass){ if ($firstPass == $secondPass) { echo "<p>Passwords match. Thank you.</p>"; } else { echo "<p>Passwords don't match. Please try again.</p>"; } } foreach ($_POST as $key=>$value) { echo "<p>".$key." = " . $value . "</p>"; } $passwords = $_POST["pword"]; echo "First password = ".$passwords[0]; echo "<br />"; echo "Second password = ".$passwords[1]; checkPasswords($passwords[0], $passwords[1]); ?> </body> </html> Когда PHP выполняет эту страницу, то описание функции пропускается, выполняется цикл foreach, выводятся значения паролей, затем вызывается функция checkPasswords() с двумя аргументами. (В качестве аргумента можно было передать и массив, тогда выделение индивидуальных значений нужно было бы сделать внутри функции.) Рисунок 12. Выполнение функции checkPasswords() после цикла foreach XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. Если у вас есть опыт программирования на других языках, то вы могли заметить, что это больше похоже на работу процедуры, а не функции, поскольку произошли некоторые действия, а главным признаком функции является то, что она возвращает некоторое значение. В PHP функции используются в обоих этих ролях. В начало Возвращаемые значения Кроме задачи выполнения некоторого сегмента кода, функции могут возвращать некоторые значения. Например, создадим функцию полной проверки правильности ввода данных таким образом, чтобы она возвращала одно значение в случае успеха и другое при наличии ошибок: ... <body> <p>You entered:</p> <?php function validate($allSubmitted){ $message = ""; $passwords = $allSubmitted["pword"]; $firstPass = $passwords[0]; $secondPass = $passwords[1]; $username = $allSubmitted["name"]; if ($firstPass != $secondPass) { $message = $message."Passwords don't match<br />"; } if (strlen($username) < 5 || strlen($username) > 50){ $message = $message."Username must be \ between 5 and 50 characters<br />"; } if ($message == ""){ $message = "OK"; } return $message; } ... В качестве аргумента функция будет принимать массив $_POST и выбирать из него информацию для проверки. В начале работы функции мы создаем пустую строку сообщений $message. Если пароль введен с ошибкой или нас не устраивает длина имени пользователя (для проверки имени использовалась функция strlen(), которая возвращает количество символов в строке), то в переменную $message добавляется некоторый текст. Если же все прошло успешно, то строка остается пустой и мы записываем в нее сообщение "OK", далее, при вызове функции мы будем проверять наличие именно этого сообщения. В начало Проверка данных Итак, мы написали функцию, которая проверяет данные и возвращает некоторое значение. Посмотрим теперь, как можно использовать это значение: ... echo "<br />"; echo "Second password = ".$passwords[1]; if (validate($_POST) == "OK") { echo "<p>Thank you for registering!</p>"; } else { echo "<p>There was a problem with your registration:</p>"; echo validate($_POST); echo "<p>Please try again.</p>"; } ?> ... В условном операторе if-then одновременно вызывается функция validate() и проверяется возвращаемое ею значение. Если проверка прошла успешно, то пользователю говорят "спасибо", а если нет -- то выводится сообщение об ошибке, как можно видеть ниже на Рисунке 13. Рисунок 13. Вывод сообщения об ошибке XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. Сделаем два замечания. Во-первых, мы надеемся, что вы оценили удобство использования функции, которая позволяет свести всю проверку к одной легко читаемой строке вместо сложной конструкции из нескольких операторов if-then. Во-вторых, заметьте, что использование функции здесь не оптимально, она вызывается дважды с одними и теми же параметрами. В большой программе это может привести к существенному снижению продуктивности, правильнее было бы вызвать функцию один раз и присвоить возвращаемое значение некоторой переменной. Теперь наши данные готовы для записи их в базу данных. Взаимодействие с базой данных MySQL Создание базы Сначала выполним необходимые подготовительные действия непосредственно в MySQL. Мы должны создать базу данных, добавить в нее таблицу и создать нового пользователя, который будет иметь доступ к базе. Находясь в консоли MySQL, наберите следующие команды: create database workflow; use workflow; create table users (id int auto_increment primary key, username varchar(50), email varchar(255), password varchar(50)); show tables; Итак, мы создали базу данных, добавили в нее таблицу users и попросили показать все таблицы нашей базы, вывод последней команды будет выглядеть так: +--------------------+ | Tables_in_workflow | +--------------------+ | users +--------------------+ 1 row in set (0.00 sec) | Наконец, создадим пользователя wfuser с паролем wfpass: GRANT ALL PRIVILEGES ON *.* TO 'wfuser'@'localhost' IDENTIFIED BY 'wfpass' WITH GRANT OPTION; Теперь мы можем перейти к использованию базы с PHP. В начало Соединение с базой данных MySQL Практически невозможно создать серьезное Web-приложение без обращения к той или иной базе данных. В нашем учебном приложении мы будем использовать базу данных MySQL для хранения имени пользователя и пароля. В этом разделе мы научимся соединяться с базой данных, принимать данные со страницы регистрации, проверять, уникально ли переданное имя пользователя и добавлять данные в базу, также вы увидите, каким образом можно вывести на страницу информацию из базы данных. Начнем с установки соединения. В PHP существует ряд функций, предназначенных для работы с MySQL, в этом разделе мы рассмотрим некоторые их них. Прежде всего, введем функцию, которая будет устанавливать соединение с базой данных, которую мы только что создали: ... return $message; } function db_connect($user='wfuser', $password='wfpass', $db='workflow'){ mysql_connect('localhost', $user, $password) or die('I cannot connect to db: ' . mysql_error()); } foreach ($_POST as $key=>$value) { echo "<p>".$key." = " . $value . "</p>"; } ... if (validate($_POST) == "OK") { echo "<p>Thank you for registering!</p>"; db_connect(); } else { echo "<p>There was a problem with your registration:</p>"; ... Итак, у нас теперь есть функция db_connect(), которая будет пытаться установить соединение между PHP и базой данных MySQL. Обратите внимание на то, что в определение функции включены не только имена, но и значения аргументов. Эти значения будут значениями "по умолчанию", они будут использоваться в том случае, если при вызове этой функции не будут определены имя пользователя, пароль или имя базы данных. Воспользовавшись этой возможностью, в нашем примере мы вызвали функцию вообще без аргументов. Вы могли заметить, что наша функция пытается открыть соединение с базой на локальной машине, об этом говорит параметр localhost. Надо иметь в виду, что машина является локальной по отношению к PHP, то есть, к Web-серверу, а не к клиенту. Если установить соединение с базой не удалось, то процесс останавливается (для этого служит опция dies) и PHP выводит текстовое сообщение об ошибке. Если все пошло успешно, то соединение с базой будет оставаться открытым до тех пор, пока вы не закроете его, или до того, когда будет закрыта страница. Все остальные команды обращения к базе данных будут ссылаться на это соединение. Последний выделенный оператор и есть, собственно, вызов нашей функции. В начало Выбор базы данных Поскольку один сервер может поддерживать несколько баз данных, то следующим шагом после открытия соединения нужно выбрать, с какой именно базой данных мы будем работать: ... function db_connect($user='wfuser', $password='wfpass', $db='workflow'){ mysql_connect('localhost', $user, $password) or die('I cannot connect to db: ' . mysql_error()); mysql_select_db($db); } ... Функцию выбора базы данных можно использовать повторно для выбора другой базы того же сервера. Следует заметить, что наши дальнейшие действия будут в известном смысле независимы от выбранной базы. Написанная нами только что функция будет единственным местом, где нужно будет внести изменения, если потребуется работать с другой базой. Теперь мы готовы к тому, чтобы добавить данные в нашу базу. В начало Добавление записей в базу Для того чтобы вставить запись в таблицу базы данных, нужно сначала написать соответствующий SQL-запрос, а затем выполнить его. Запрос будет иметь следующую форму: insert into users (username, email, password) values ('roadnick', 'ibmquestions@nicholaschase.com', 'supersecretpassword') Вы могли заметить, что в этом запросе использованы не все поля таблицы users, поле с именем id пропущено. Дело в том, что это поле имело атрибут AUTO_INCREMENT, в том случае, если его значение пропущено в запросе, MySQL подставляет первое свободное целое число. Теперь попытаемся поместить в базу данных реальные данные из нашей формы регистрации, то есть, выполнить запрос: ... if (validate($_POST) == "OK") { echo "<p>Thank you for registering!</p>"; db_connect(); $sql = "insert into users (username, email, password) values ('".$_POST["name"]."', '".$_POST["email"]."', '".$passwords[0]."')"; $result = mysql_query($sql); \ if ($result){ echo "It's entered!"; } else { echo "There's been a problem: ".mysql_error(); } } else { echo "<p>There was a problem with your registration:</p>"; ... Обратите внимание на то, что функция, которая выполняет запрос, mysql_query(), возвращает значение логического типа, которое записывается в переменную $result. Если запрос отработал успешно, то значение будет "истина" (TRUE), а если возникли те или иные проблемы, то значение будет "ложь" (FALSE). Это значение можно затем использовать в условных операторах if-then, для того чтобы предпринять те или иные действия. Если возникли какие-либо проблемы, MySQL передаст сообщение об ошибке в функцию mysql_error() и это сообщение можно будет вывести на странице. Посмотрим теперь, как извлекается информация из базы данных. В начало Выбор записей из базы Итак, мы умеем записывать наши данные в базу. Но как мы можем узнать, уникально ли предложенное имя пользователя? Посмотрим, как можно проверить имя, прежде чем добавлять данные: ... if (validate($_POST) == "OK") { echo "<p>Thank you for registering!</p>"; db_connect(); $sql = "select * from users where username='".$_POST["name"]."'"; $result = mysql_query($sql); if (!$result) { $sql = "insert into users (username, email, password) values ('".$_POST["name"]."', '".$_POST["email"]."', '".$passwords[0]."')"; $result = mysql_query($sql); if ($result){ echo "It's entered!"; } else { echo "There's been a problem: ".mysql_error(); } } else { echo "There is already a user with that name: <br />"; $sqlAll = "select * from users"; $resultsAll = mysql_query($sqlAll); } } else { echo "<p>There was a problem with your registration:</p>"; ... Первый SQL-запрос выбирает из базы все записи, у которых значение поля username совпадает с именем пользователя, которое мы планируем вставить. Если такие записи были найдены, то функция mysql_query() возвращает TRUE, а если нет – то FALSE. Поскольку мы хотим вставлять только уникальные имена, то для нас желательным значением переменной $result будет FALSE. Но условный оператор выполняет первый сегмент кода в том случае, если значение условного выражения равно TRUE. Конечно, мы могли бы поместить вставку записи в базу данных после ключевого слова else но для того, чтобы сделать нашу программу изящнее, мы применили к переменной $result оператор инверсии (представленный восклицательным знаком), которой меняет логическое значение на противоположное. Что произойдет, если совпадающее значение будет найдено и переменная $result будет иметь значение TRUE? Тогда значение выражения !$result будет FALSE, и программа перейдет к выполнению сегмента else. Мы сообщим пользователю о том, что введенное имя уже существует и выполним SQL-запрос, который выбирает все данные из нашей таблицы. В начало Получение данных из базы Безусловно, в реальных условиях никому не придет в голову в подобной ситуации показать все записи таблицы. Мы выведем данные только в качестве тренировки, чтобы вы посмотрели, как это делается. Выше мы создали и выполнили SQL-запрос, который выбирает все записи из таблицы users и записали результат в переменную $resultsAll. Очевидно, что эта переменная имеет сложную структуру. Посмотрим, как извлечь из нее данные: ... } else { echo "There is already a user with that name: <br />"; $sqlAll = "select * from users"; $resultsAll = mysql_query($sqlAll); $row = mysql_fetch_array($resultsAll); echo $row["username"]." -- ".$row["email"]."<br />"; } ... Итак, для извлечения данных из переменной $resultsAll была использована функция mysql_fetch_array(), эта функция возвращает ассоциативный массив, соответствующий набору данных одной записи в таблице. Ключами массива являются имена полей таблицы. Запишем этот массив в переменную $row и затем извлечем из нее значения по ключам. Да, но такой способ позволяет работать только с одной строкой таблицы. Каким образом получить доступ ко всем данным? В начало Просмотр результатов: цикл while Если в результате выполнения запроса была выбрана хотя бы одна строка, то логическое значение переменной $row будет TRUE. Это обстоятельство можно использовать в условных операторах if-then или в циклах while. На первом шаге цикла значение условного выражения в скобках будет TRUE, поэтому начнет выполняться блок операторов. Данные массива отображаются на странице, затем делается попытка получить следующую строку. ... } else { echo "There is already a user with that name: <br />"; $sqlAll = "select * from users"; $resultsAll = mysql_query($sqlAll); $row = mysql_fetch_array($resultsAll); while ($row) { echo $row["username"]." -- ".$row["email"]."<br />"; $row = mysql_fetch_array($result); } } ... Цикл будет продолжаться до тех пор, пока остаются строки для обработки. После того как обработана последняя строка, функция mysql_fetch_array() вернет FALSE, цикл прервется и начнут выполняться операторы, стоящие после цикла. Будьте внимательны. Если вы пропустите последний шаг в цикле, то есть не извлечете следующую строку, то значение условного выражения всегда будет истинным и ваш цикл станет бесконечным. Хорошим правилом при написании циклов while будет вставлять операторы обновления условия в тело цикла в первую очередь. В начало Закрыть соединение с базой данных Прежде чем двигаться дальше, закроем соединение с нашей базой данных: ... if (validate($_POST) == "OK") { echo "<p>Thank you for registering!</p>"; db_connect(); $sql = "select * from users where username='".$_POST["name"]."'"; $result = mysql_query($sql); if (!$result) { ... } mysql_close(); } else { ... Теперь настало время навести порядок в структуре наших файлов. Наведем порядок: включение кода из файлов Зачем нужно включение кода из файлов? До сих пор весь код нашего скрипта хранился в одном PHP-файле. В этом разделе мы перераспределим его по нескольким файлам и изучим операторы включения. Причина появления такого механизма, как включение, в том, что некоторые сегменты кода используются на многих страницах, и выделение их в отдельный файл помогает избежать дублирования и упростить сопровождение кода. В PHP существует два оператора включения файлов. Один из них используется для включения обычной информации, например, заголовков или сообщений, а другой -- для критической, например, для включения функций, вызываемых из Web-страницы. В начало Файлы для включения Начнем работу с создания файла, который будет впоследствии использоваться в операторе включения. Как бы ни выглядела ваша Web-страница, у нее должен быть заголовок и нижний колонтитул, в которых содержатся элементы навигации. Мы поместим заголовок в отдельный файл и затем будем включать его в большое число страниц, все они будут выглядеть однотипно. Если мы захотим внести изменения во внешний вид наших страниц, то нам надо будет сделать это только один раз. Для начала создадим файл с именем top.txt и включим в него следующий текст: <html> <head> <title>Workflow System</title> </head> <body> <table> <tr><td colspan="2"><h2>The Workflow System</h2></td></tr> <tr> <td width="30%"> <h3>Navigation</h3> <p><a href="register.php">Register</a></p> </td> <td> Во второй файл, который мы назовем bottom.txt, добавьте следующие строки: </td> </tr> </table> </body> </html> Сохраните файлы в том же каталоге, где уже находится файл registration.php. В начало Оператор включения include Теперь включим созданные нам файлы в страницу регистрации. Внесите в файл registration.php следующие изменения: <?php include("top.txt"); ?> <h1>Register for an Account:</h1> <form action="registration_action.php" method="POST"> Username: <input type="text" name="name" /><br /> Email: <input type="text" name="email" /><br /> Password: <input type="password" name="pword[]" /><br /> Password (again): <input type="password" name="pword[]" /><br /> <input type="submit" value="GO" /> </form> <?php include("bottom.txt"); ?> Мы убрали текст, с которого начинается и которым заканчивается обычно HTML-страница и добавили два оператора include с именами только что созданных файлов. Посмотрим, какова будет реакция браузера на эти изменения. В начало Посмотрим на результаты Обновите страницу регистрации в браузере и вы увидите, что ее внешний вид сильно переменился, новый вариант показан на Рисунке 14. Рисунок 14. Новый вид регистрационной страницы XML error: The image is not displayed because the width is greater than the maximum of 500 pixels. Please decrease the image width. Если вы нажмете клавишу просмотра исходного кода страницы в своем браузере, то увидите, что в нем объединены все три файла: <html> <head> <title>Workflow System</title> </head> <body> <table> <tr><td colspan="2"><h2>The Workflow System</h2></td></tr> <tr> <td width="30%"> <h3>Navigation</h3> <p><a href="register.php">Register</a></p> </td> <td> <h1>Register for an Account:</h1> <form action="registration_action.php" method="POST"> Username: <input type="text" name="name" /><br /> Email: <input type="text" name="email" /><br /> Password: <input type="password" name="pword[]" /><br /> Password (again): <input type="password" name="pword[]" /><br /> <input type="submit" value="GO" /> </form> </td> </tr> </table> </body> </html> Внесите такие же изменения в файл registration_action.php и отошлите данные регистрации, ваша вторая страница будет иметь новый внешний вид, сходный с первой. Конечно, нашу страницу нельзя назвать произведением искусства, но она работает. Позже, когда вы найдете дизайнера и придумаете как сделать ее красивее, вам придется внести все изменения только один раз, во включаемые файлы, и внешний вид всех ваших страниц изменится как по волшебству. В начало Оператор включения require Если PHP не может найти файла заголовка или нижнего колонтитула, то это плохо, но не катастрофично, приложение все равно будет работать. Если отсутствует файл, указанный в операторе include, PHP выводит предупреждение и продолжает обработку страницы. Однако в некоторых случаях отсутствие включаемого файла является катастрофой. Например, мы могли решить, что полезно поместить описание функций validate() и db_connect() в отдельный файл и затем включить этот файл в registration_action.php при помощи оператора include. Если PHP не сможет найти файла с функциями, но не прекратит работу, то возникнет масса проблем. Для того чтобы предотвратить эту ситуацию, следует использовать оператор require вместо include: <?php include("top.txt"); require("scripts.txt"); ?> <p>You entered:</p> <?php foreach ($_POST as $key=>$value) { echo "<p>".$key." = " . $value . "</p>"; } $passwords = $_POST["pword"]; echo "First password = ".$passwords[0]; echo "<br />"; echo "Second password = ".$passwords[1]; if (validate($_POST) == "OK") { echo "<p>Thank you for registering!</p>"; ... В целом оператор require работает также, как и include, но если PHP не может найти включаемого файла, то он сообщает о фатальной ошибке и выполнение скрипта прекращается. В начало Предупреждение возникновения дубликатов. Нет никаких препятствий к тому, чтобы включаемый файл сам содержал в себе оператор include. Но в том случае, если структура подключаемых файлов становится слишком сложной, есть риск включить один и тот же файл несколько раз. Кроме испорченного интерфейса от этого могут произойти и другие неприятности, например, ошибки, связанные с переопределением функций или констант. Для предупреждения повторного включения файлов в PHP существуют специальные версии операторов включения include и require, ниже вы можете видеть пример их использования: <?php include_once("top.txt"); require_once("scripts.txt"); ?> <p>You entered:</p> <?php foreach ($_POST as $key=>$value) { echo "<p>".$key." = " . $value . "</p>"; } ... Когда PHP встречает операторы include_once или require_once, то происходит проверка, не было ли включения указанных файлов ранее, таким образом предупреждается включение файлов-дубликатов. Подведем итоги В этом пособии мы начали знакомство с языком программирования PHP с создания простого Web-приложения. Вы изучили основы синтаксиса PHP-скриптов, узнали как можно передавать данные при помощи HTML-форм, познакомились с такими базовыми понятиями как переменная, условный оператор и цикл. Мы определили понятие массива данных, рассмотрели ассоциативные массивы и массивы с числовыми индексами, способы доступа к данным массивов. Вы научились просматривать и отсылать данные в базу данных MySQL при помощи формирования и выполнения SQL-запросов, узнали каким образом можно обработать строку данных из таблицы базы. Наконец, мы рассмотрели операторы включения файлов, которые позволяют оптимизировать структуру Web-приложения. Цель этой серии учебных пособий -- научить вас создавать с помощью PHP приложения, поддерживающие workflow. В первой части серии мы начали процесс с создания страницы, на которой пользователь вводит новую учетную запись, мы проверяем ее и помещаем в базу данных. В следующей части этой серии мы научимся использовать процедуру HTTP-аутентификации и загрузку документов с сервера, рассмотрим использование формата XML и другие вопросы, которые помогут вам в освоении программирования на PHP.