§10. Работа с формами
10.1. Простая отправка текстовых данных.
Как было показано ранее в курсе HTML, для отправки пользовательских данных на сервер используются формы. В данном параграфе мы рассмотрим данный вопрос подробнее.
Внимательно посмотрите на код формы, представленный в примере 10.1.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Отправка простых текстовых данных</title> </head> <body> <form action="example_10_2.php" method="POST" name="form_10_1"> Введите имя <input type="text" name="firstName"><br><br> Введите фамилию <input type="text" name="lastName"><br><br> Предпочитаете <input type="radio" name="user_choice" value="овощи" checked>овощи <input type="radio" name="user_choice" value="фрукты">фрукты<br><br> <button type="submit" name="submit" value="send">Отправить</button> </form> </body> </html>
Пример 10.1. Форма для отправки простых текстовых данных
Атрибут action формы устанавливает обработчик данных формы на сервере. При этом путь к php-файлу может быть указан как абсолютным, так и относительным. В нашем случае скрипт находится в той же папке, что и веб-страница с формой.
Атрибут method определяет метод запроса на сервер: POST или GET. Однако учитывая то, что формы зачастую используются для отправки конфиденциальных данных пользователей, а также файлов, практически всегда используется метод POST.
Что касается атрибута target то, если он в форме не указан (наш случай), возвращаемый результат будет отображаться в текущем окне.
Каким же образом данные из формы передаются на сервер? Все очень просто, они отправляются в виде пар 'name'='value', где 'name' – значение атрибута name, а 'value' – значение атрибута value, которое может быть установлено заранее (например, для кнопок) или же принимать значение в зависимости от введенных пользователем данных. После отправки данных формы на сервер методом POST, они становятся доступны php-скрипту через суперглобальный ассоциативный массив данных $_POST, а при отправке методом GET – через суперглобальный ассоциативный массив данных $_GET. Кроме того, данные можно получить и через суперглобальный ассоциативный массив данных $_REQUEST, который по умолчанию содержит данные переменных $_GET, $_POST и $_COOKIE. Отметим, что посмотреть все предопределенные переменные, основная масса которых представляет собой такие суперглобальные массивы, можно в официальном справочнике в разделе Руководство по PHP -> Справочник языка -> Предопределенные переменные.
Обратите внимание, что при использовании для передачи данных кнопок или флажков, данные не вводятся, а выбираются. Поэтому у таких элементов заранее указывается атрибут value, значение которого в случае выбора и будет отправлено на сервер.
Пусть, например, обработчик на сервере имеет код, показанный в примере 10.2. Тогда при вводе в текстовые поля формы значений 'Иван' и 'Бочкин', а также выборе варианта 'фрукты', при успешной отправке и обработке данных нашей формы мы увидим на экране строку 'Иван Бочкин любит фрукты'.
<?php //Чтобы не усложнять пример, будем считать, что все данные были введены //Достаем полученные данные из суперглобального массива $_POST //и присваиваем их переменным для удобства использования $firstName = $_POST["firstName"]; $lastName = $_POST["lastName"]; $user_choice = $_POST["user_choice"]; //Выводим сообщение echo $firstName.' '.$lastName.' любит '.$user_choice; ?>
Пример 10.2. Обработка данных, переданных на сервер формой примера 10.1
10.2. Передача текстовых данных в массивах.
В PHP также имеется возможность обрабатывать данные переданные формой в массивах. Рассмотрим данную возможность на примере 10.3.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Отправка данных в массивах</title> </head> <body> <form action="example_10_4.php" method="POST" name="form_10_3"> Введите имя <input type="text" name="personal[firstName]"><br><br> Введите фамилию <input type="text" name="personal[lastName]"><br><br> Предпочитаете <input type="checkbox" name="choice[]" value="овощи">овощи <input type="checkbox" name="choice[]" value="фрукты">фрукты<br><br> <button type="submit" name="submit" value="send">Отправить</button> </form> </body> </html>
Пример 10.3. Передача текстовых данных в массивах
Как видно из примера, данные можно группировать в массивы. В нашем случае для первых двух полей мы использовали массив personal с двумя элементами: personal[firstName] и personal[lastName] (ключи в кавычки брать не нужно). В результате этого, после отправки данных формы на сервер, значения, введенные пользователем в поля формы, будут доступны в php-скрипте через $_POST["personal"]["firstName"] и $_POST["personal"]["lastName"] (в самом скрипте кавычки лучше указывать). Если ключи элементов массивов в форме не указать, им будут присвоены числовые ключи. При чем, значение элемента формы, который идет в коде первым, станет первым элементом массива, значение элемента формы, который следует за ним, вторым элементом массива и т.д. В примере мы не указывали ключи элементов массива choice, поэтому на сервере значения, введенные пользователем в поля формы, будут доступны через $_POST["choice"][0] и $_POST["choice"][1]. Данная ситуация показана в примере 10.4.
<?php //Чтобы не усложнять пример, будем считать, что все данные были введены //Достаем полученные данные из суперглобального массива $_POST //и присваиваем их переменным для удобства использования $firstName = $_POST["personal"]['firstName']; $lastName = $_POST["personal"]['lastName']; //Поскольку в форме мы индексы не указывали, им были назначены числовые индексы //согласно их появлению в коде html (индексация начинается с нуля) $user_choice_0 = $_POST["choice"][0]; $user_choice_1 = $_POST["choice"][1]; //Выводим сообщение echo $firstName.' '.$lastName.' любит '.$user_choice_0.' и '.$user_choice_1; ?>
Пример 10.4. Обработка данных, переданных на сервер формой примера 10.3
Передача текстовых данных в массивах может быть весьма удобна при использовании элемента 'select' с заданным атрибутом multiple, который позволяет выбирать сразу несколько элементов списка (см. пример 10.5).
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Отправка данных в массивах</title> </head> <body> <form action="example_10_6.php" method="POST" name="form_10_5"> фрукты: <select multiple name="fruits[]" size="3"> <option value="яблоки">Яблоки</option> <option value="апельсины">Апельсины</option> <option value="лимоны">Лимоны</option> </select> <br><br> <button type="submit" name="submit" value="send">Отправить</button> </form> </body> </html>
Пример 10.5. Использование массива для передачи данных в элементе 'select'
При выборе нескольких значений из списка они будут автоматически добавляться в созданный массив fruits в качестве элементов fruits[0], fruits[1] и т.д., что особенно удобно при большом количестве вариантов.
Напомним, что для выбора нескольких пунктов списка нужно использовать клавиши Ctrl и Shift.
В качестве обработчика данной формы используем php-скрипт примера 10.6. В нем мы в качестве примера присвоили переменной весь переданный массив fruits, а уже затем использовали переменную для получения значений элементов массива по их числовым ключам.
<?php //Чтобы не усложнять пример, будем считать, что все данные были введены //Достаем из суперглобального массива $_POST сразу весь массив fruits $fruits = $_POST['fruits']; echo 'Вы выбрали все фрукты: '.$fruits[0].', '.$fruits[1].' и '.$fruits[2]; ?>
Пример 10.6. Обработка данных, переданных на сервер формой примера 10.5
10.3. Загрузка пользовательских файлов на сервер.
Довольно часто возникает необходимость отправки на сервер не только текстовых данных, но и отдельных пользовательских файлов, например, фотографий. В таком случае алгоритм действий также довольно прост и понятен, однако несколько сложнее передачи простых текстовых данных. Код формы с полем для загрузки файла на сервер показан в примере 10.7.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Загрузка одиночных файлов</title> </head> <body> <form action="example_10_8.php" method="POST" name="form_10_7"> Введите имя: <input type="text" name="firstName"><br><br> Введите фамилию: <input type="text" name="lastName"><br><br> <input type="hidden" name="MAX_FILE_SIZE" value="30000"> Загрузите аватарку (не более 30кб):<br><br> <input type="file" formenctype="multipart/form-data" name="userFile"><br><br> <button type="submit" name="submit" value="send">Отправить</button> </form> </body> </html>
Пример 10.7. Код формы с полем для загрузки одиночных файлов на сервер
Скрытое поле должно предшествовать полю для выбора файла. Его атрибуты name = "MAX_FILE_SIZE" и value = "30000" задают максимально допустимый размер загружаемого файла. Рекомендуется всегда использовать данные параметры, т.к. это предотвращает ненужное ожидание пользователей при передаче огромных файлов только для того, чтобы узнать, что файл слишком большой и его передача не состоялась. Конечно, обойти это ограничение на стороне браузера достаточно просто, следовательно, не стоит полагаться на то, что все файлы большего размера будут блокированы при помощи этой возможности. Однако на сервере настройки касательно максимального размера загружаемых файлов обойти практически невозможно.
Если в поле для отправки файлов задать атрибут accept, то в дополнение к ограничению на размер передаваемого файла будет наложено ограничение и на возможные типы передаваемых файлов. Если файл не будет соответствовать фильтру, устанавливаемому данным атрибутом, пользователь не увидит его в окне выбора файлов. Если атрибут не применяется, то в окне выбора файлов будут показываться все файлы, доступные для просмотра.
Следует отметить, что для отправки файлов нужно обязательно указывать значение атрибута enctype = "multipart/form-data", вместо значения enctype = "application/x-www-form-urlencoded" элемента 'form', иначе загрузка файлов на сервер выполняться не будет.
После загрузки файла на сервер всю информацию о нем можно узнать из глобального массива $_FILES:
- $_FILES['userfile']['name'] – оригинальное имя файла на компьютере клиента;
- $_FILES['userfile']['type'] – mime-тип файла, например, "image/gif"; полагаться на его значение без проверки не стоит;
- $_FILES['userfile']['size'] – размер в байтах принятого файла;
- $_FILES['userfile']['tmp_name'] – временное имя, с которым принятый файл был сохранен на сервере (точнее путь к файлу во временной папке, где ему присваивается временное имя);
-
$_FILES['userfile']['error'] – код ошибки, которая может возникнуть при загрузке файла:
- UPLOAD_ERR_OK – значение: 0; файл был успешно загружен на сервер;
- UPLOAD_ERR_INI_SIZE – значение: 1; размер принятого файла превысил максимально допустимый размер, который установлен в директиве upload_max_filesize конфигурационного файла php.ini;
- UPLOAD_ERR_FORM_SIZE – значение: 2; размер загружаемого файла превысил значение "MAX_FILE_SIZE", указанное в HTML-форме;
- UPLOAD_ERR_PARTIAL – значение: 3; загружаемый файл был получен только частично;
- UPLOAD_ERR_NO_FILE – значение: 4; файл не был загружен;
- UPLOAD_ERR_NO_TMP_DIR – значение: 6; отсутствует временная папка;
- UPLOAD_ERR_CANT_WRITE – значение: 7; не удалось записать файл на диск;
- UPLOAD_ERR_EXTENSION – значение: 8; какое-то из PHP-расширений остановило загрузку файла, при этом PHP не предоставляет способа определить, какое именно; в этом может помочь просмотр списка загруженных расширений из phpinfo().
Использование суперглобального массива $_FILES показано в примере 10.8.
<?php //Предполагается, что файл был успешно загружен $userFile = $_FILES['userFile']['name']; echo 'Имя вашего файла: '.$userFile.'<br>'; $userFileType = $_FILES['userFile']['type']; echo 'Тип вашего файла: '.$userFileType.'<br>'; $userFileSize = $_FILES['userFile']['size']; echo 'Размер вашего файла: '.$userFileSize.' байт'.'<br>'; $userFileTmp = $_FILES['userFile']['tmp_name']; echo 'Временное имя файла на сервере: '.$userFileTmp.'<br>'; $userFileError = $_FILES['userFile']['error']; echo 'Код ошибки: '.$userFileError.'<br>'; ?>
Пример 10.8. Обработка данных, переданных на сервер формой примера 10.7
Если нужно загрузить несколько файлов, то можно либо использовать в поле для отправки файлов атрибут multiple (см. пример 10.9), либо не одно, а несколько соответствующих элементов 'input'. При этом, если размер какого-либо из файлов превысит значение "MAX_FILE_SIZE", он загружен не будет. Однако это не повлияет на загрузку остальных файлов, поэтому желательно сообщать о такой ситуации пользователю выводом соответствующего сообщения.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Загрузка нескольких файлов</title> </head> <body> <form action="example_10_10.php" method="POST" enctype="multipart/form-data"> Введите имя: <input type="text" name="firstName"><br><br> Введите фамилию: <input type="text" name="lastName"><br><br> <input type="hidden" name="MAX_FILE_SIZE" value="3000000"> Загрузите аватарки (не более 3Мб каждая):<br><br> <input type="file" name="userFile[]" multiple><br><br> <button type="submit" name="submit" value="send">Отправить</button> </form> </body> </html>
Пример 10.9. Код формы с полем для загрузки нескольких файлов на сервер
При использовании атрибута multiple в качестве значения атрибута name нужно использовать массив, иначе на сервере мы сможем получить данные только о последнем загруженном файле. После загрузки файлов на сервер доступ к ним может быть получен, опять же, через суперглобальный массив $_FILES, с учетом того, что файлам в массиве будут назначены числовые ключи согласно порядку их отправки (см. пример 10.10).
<?php //Будем считать, что как минимум один файл был загружен //Выводим информацию о первом из загруженных файлов $userFile = $_FILES['userFile']['name'][0]; echo 'Имя вашего файла: '.$userFile.'<br>'; $userFileType = $_FILES['userFile']['type'][0]; echo 'Тип вашего файла: '.$userFileType.'<br>'; $userFileSize = $_FILES['userFile']['size'][0]; echo 'Размер вашего файла: '.$userFileSize.' байт'.'<br>'; $userFileTmp = $_FILES['userFile']['tmp_name'][0]; echo 'Временное имя файла на сервере: '.$userFileTmp.'<br>'; $userFileError = $_FILES['userFile']['error'][0]; echo 'Код ошибки: '.$userFileError.'<br>'; ?>
Пример 10.10. Обработка данных, переданных на сервер формой примера 10.9
В случаях, когда необходимо по-разному ограничить размеры загружаемых файлов, следует выбирать второй вариант, используя несколько полей для отправки файлов и указывая перед каждым из них скрытое поле с требуемым ограничением размера (см. пример. 10.11). Кроме того, к файлам можно будет обращаться по их ключам, хотя можно поступить и предыдущим способом, просто объявив общий массив.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Загрузка нескольких файлов</title> </head> <body> <form action="example_10_12.php" method="POST" enctype="multipart/form-data"> Введите имя: <input type="text" name="firstName"><br><br> Введите фамилию: <input type="text" name="lastName"><br><br> Загрузите фото (не более 1Мб): <input type="hidden" name="MAX_FILE_SIZE" value="1000000"> <input type="file" name="file_1"><br><br> Загрузите аватарку (не более 50Кб): <input type="hidden" name="MAX_FILE_SIZE" value="50000"> <input type="file" name="file_2"><br><br> <button type="submit" name="submit" value="send">Отправить</button> </form> </body> </html>
Пример 10.11. Код формы с несколькими полями загрузки файлов
<?php //Будем считать, что оба файла были загружены //Выводим информацию о результатах загрузки файлов $fileName_1 = $_FILES['file_1']['name']; echo 'Имя вашего файла: '.$fileName_1.'<br>'; $fileError_1 = $_FILES['file_1']['error']; echo 'Код ошибки: '.$fileError_1.'<br>'.'<br>'; $fileName_2 = $_FILES['file_2']['name']; echo 'Имя вашего файла: '.$fileName_2.'<br>'; $fileError_2 = $_FILES['file_2']['error']; echo 'Код ошибки: '.$fileError_2.'<br>'.'<br>'; ?>
Пример 10.12. Обработка данных, переданных на сервер формой примера 10.11
В процессе загрузки файлов на сервер они помещаются во временную папку, которая задается в настройках конфигурационного файла php.ini (подробно рассмотрим позже). Для того, чтобы переместить файл из временной папки в нужное место, нужно использовать функцию move_uploaded_file(), которая проверяет, является ли файл загруженным на сервер по протоколу HTTP POST, и в случае удачи перемещает загруженный файл в новое место, возвращая при этом true (см. пример 10.13). Если же перемещение по каким-либо причинам невозможно, функция вернет false (см. раздел 'Расширения для работы с файловой системой' официального справочника).
<?php //Переместим файл, загруженный при помощи формы примера 10.7, в папку loaded_files //Сохраним путь к файлу во временной папке в переменной $userFileTmp = $_FILES['userFile']['tmp_name']; //Сохраним в переменной исходное имя загруженного файла $file_name = $_FILES['userFile']['name']; //Путь построим от корня сайта '/' и заменим временное имя файла обратно на свое $my_dir="/loaded_files/{$file_name}"; //Если файл будет перемещен, функция вернет true if(move_uploaded_file($userFileTmp, $my_dir)){ echo "Файл корректен и был успешно перемещен."; }else{ echo "Файл не был перемещен!"; } ?>
Пример 10.13. Перемещение загруженных файлов из временной папки
Если требуется переместить сразу несколько файлов, загруженных при помощи поля с атрибутом multiple (см. пример 10.9 и пример 10.10), можно воспользоваться, например, циклом foreach, повторив процедуру перемещения для всех элементов массива.
10.4. Использование php-скрипта и html-формы в одном файле.
Во всех предыдущих примерах мы использовали по отдельности файл с формой и с обработчиком формы. Однако довольно часто в ходе разработки сайта бывает полезным совмещать в одном файле коды сразу нескольких языков (и не обязательно только HTML и PHP). Рассмотрим такую ситуацию на примере 10.14.
<?php //Чтобы не создавать два файла, совместим все в одном php-файле. Весь html-код //с помощью синтаксиса heredoc присвоим переменной и выведем только в том //случае, если форма еще не была отправлена на сервер //$_SERVER['PHP_SELF'] содержит имя текущего скрипта относительно корня документа $a=<<<HD <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Отправка простых текстовых данных</title> </head> <body> <form action="{$_SERVER['PHP_SELF']}" method="POST"> Введите имя <input type="text" name="firstName"><br><br> Введите фамилию <input type="text" name="lastName"><br><br> Предпочитаете <input type="checkbox" name="choice[]" value="овощи">овощи <input type="checkbox" name="choice[]" value="фрукты">фрукты<br><br> <button type="submit" name="submit" value="send">Отправить</button> </form> </body> </html> HD; //Если форма была уже отправлена, то в массиве уже есть элемент $_POST["submit"] if(isset($_POST["submit"])){ //Чтобы не усложнять пример, будем считать, что все данные были введены //Достаем полученные данные из суперглобального массива $_POST //и присваиваем их переменным для удобства использования $firstName = $_POST['firstName']; $lastName = $_POST['lastName']; $user_choice_0 = $_POST["choice"][0]; $user_choice_1 = $_POST["choice"][1]; //Выводим сообщение echo $firstName.' '.$lastName.' любит '.$user_choice_0.' и '.$user_choice_1; }else{ //Если же форма еще не была отправлена выводим ее echo $a; } ?>
Пример 10.14. Код формы, которая ссылается сама на себя
Использование в одном файле как формы, так и ее обработчика, особенно удобно, когда необходимо отобразить форму пользователю повторно в случае неправильного заполнения некоторых полей. При чем форма обычно возвращается не пустой, а с верно заполненными полями и пометками, какие поля нужно заполнить заново.
Словарь новых английских слов
request [rɪˈkwɛst] – запрос, заявка. choice [tʃɔɪs] – выбор. |
application [ˌæplɪˈkeɪʃn] – приложение. upload [ˌʌpˈləʊd] – загружать. |