Найти тему

Урок 15. Закомимся с Ajax, GET и POST. Отправляем форму с сайта на сервер.

Оглавление

Сегодня будем отправлять форму заявки на вступление в клуб с сайта на сервер и там обрабатывать. Разберемся, каким образом браузер может обмениваться данными с сервером.

Что было на прошлом занятии?

Урок 14. Знакомимся с PHP, Docker, NginX. Обучение веб-программированию с нуля.
Обучение веб-программированию с нуля бесплатно12 сентября 2022
  • Разобрались, что такое виртуализация и контейнеры
  • Разобрались в общих чертах, как обрабатываются запросы браузера на сервере
  • Разобрались и настроили веб-сервер NginX
  • Создали контейнеры NginX и php в Docker
  • Подняли у себя на компьютере локально Docker-сервис
  • Познакомились с языком программирования php

Что будет на этом уроке?

На этом уроке мы:

  • Соберем результаты прошлых уроков в один проект
  • Разберемся, каким образом можно отправлять формы с сайта на сервер
  • Разберемся, как обрабатывать на сервере данные, отправленные с браузера

Если в процессе изучения что-то не понятно - не стесняйтесь спрашивать нас и других учеников в нашей открытой группе в телеграм:

SRMT22 Открытый клуб веб-разработки

Для тех, кто только к нам присоединился, ссылка на все уроки:

https://zen.yandex.ru/srmt22_webclasses

И ссылка на самый первый урок:

https://dzen.ru/media/id/62d57767cc38491671976547/62d577ce6a8de461fac89852

Собираем проекты в один.

Создайте папку нового проекта. У меня это будет srmt22-lsn15.

За основу возьмем проект с Урока 14.

https://github.com/madmaker/srmt22-lsn14/archive/refs/tags/v1.zip

Качайте, распаковывайте и копируйте все файлы в папку нового проекта.

Теперь скачайте проект с урока 13, распакуйте и все содержимое сложить в папку www в новом проекте.

https://github.com/madmaker/srmt22-lsn13/archive/refs/tags/v1.zip

Теперь откройте папку нового проекта в IDE (phpstorm, vscode или другая).

У нас получилась вот такая структура папок:

-2

Давайте удалим лишние файлы:

/www/README.md - это файл от проекта lsn13. Такой же уже есть в корне от lsn14

/www/.gitignore - это файл от проекта lsn13. Такой же уже есть в корне от lsn14

/www/jsconfig.json - этот файл сделал vscode автоматически. Он не нужен.

Папку scss из /www/scss переместите на уровень выше - в корень. Будет /scss

Файл /www/index.php удалите.

Файл /www/index.html переименуйте в /www/index.php

О да, в php-сценариях может быть обычный html. Php-интерпретатор его не будет обрабатывать и выведет как есть.

Получилось вот так:

-3

Теперь время поднять контейнеры.

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

Как погасить контейнеры Docker

  • Открываем Терминал
  • Вводим команду docker container ls - эта команда выведет список запущенных контейнеров.
-4

Докер выведет список запущенных контейнеров. Если список пуст, то просто пропустите этот шаг.

Container ID - это идентификатор контейнера. Нам нужно их погасить.

Копируем ID первого контейнера и выполняем следующую команду:

docker container stop XXXXXX

XXXXXX - ID вашего контейнера.

У меня было так: docker container stop 9cc9e3fe2f45

В ответ выведет номер остановленного контейнера:

-5

Повторяем все, пока список контейнеров не станет пустым.

Кстати, последние команды в терминале можно найти, нажав на клавишу "вверх" на клавиатуре.

Дальше по алгоритму:

  • docker container ls
  • Копируем ID очередного контейнера
  • docker container stop XXXXX
  • Повторяем, пока список запущенных контейнеров не будет пустым.
-6

Еще один нюанс: у нас в прошлом уроке был создан контейнер с именем nginx. В этом проекте мы будем создавать такой контейнер и, разумеется получим ошибку. Поэтому контейнер с именем nginx нужно удалить.

Выполните команду:

docker container rm nginx
-7

Контейнер будет удален.

Теперь поднимаем контейнеры нашего проекта.

В терминале в IDE выполните следующую команду:

docker-compose up
-8

Результат запуска будет вроде такого:

-9

Проверьте результат в Chrome: откройте адрес или 127.0.0.1, или localhost

-10

Отправляем веб-форму на сервер

Итак, когда мы нажимаем на кнопку "Вступить в клуб бесплатно", у нас открывается диалог с веб-формой, которую мы делали.

Когда пользователь нажмет в форме кнопку "Поехали", нужно эту форму отправить на сервер. Давайте разбираться, как это делать.

-11

Отправка формы без JS штатным путем.

У нас в 232-й строке файла index.php находится html-код формы.

<form>
<label for="phone">Телефон для связи</label>
<input type="tel" name="phone" pattern="\+[0-9]{9,13}" placeholder="+79991112233" required>
<button type="submit">Поехали!</button>
</form>

Для тега form существует атрибут action, который задает адрес, на который будет отправлена форма.

Изменим код таким образом:

<form action="enterToClubFormHandler.php">

Этот код говорит о том, что форма будет отправляться к скрипту enterToClubFormHandler.php.

Обновите страницу в Chrome и попробуйте заполнить форму и нажать "Поехали" - таким образом вы отправите форму.

-12

Поздравляю, форма успешно отправилась на сервер. Ошибка 404 говорит о том, что скрипт enterToClubFormHandler.php на сервере не найден.

И, кстати, все отработало в точности, как мы описывали в nginx.conf на прошлом уроке - если файл не найден, то выводится ошибка 404.

Теперь давайте создадим файл enterToClubFormHandler.php в папке www.

Нажмите в браузере "Назад", обновите страницу и попробуйте отправить форму заново.

Теперь результат будет другим - пустая страница. Опять же, все верно: php-скрипт enterToClubFormHandler.php теперь есть, но он ничего не делает и ничего не выводит.

Давайте в скрипт, обрабатывающий форму, напишем следующий код:

<?php
print_r($_GET);

Напомню, <?php дает php-интерпретатору понять, что дальше идет php-код и его нужно обрабатывать.

print_r()

Функция, выводящая массив на экран (про массивы ниже расскажу).

$_GET - переменная, содержащая в себе массив, переданный на сервер в URL.

Передача данных GET-запросом

Обратите внимание на URL страницы (в адресной строке браузера)

-13

http://127.0.0.1/enterToClubFormHandler.php?phone=%2B79998887766

С адресом до знака вопроса все ясно - это адрес нашего php-скрипта на нашем локальном сервере.

А дальше идут GET-параметры. А именно те, которые передаются с нашей формы. phone - номер телефона. Слово phone взято из атрибута name поля формы, которую мы делали. А значение взято из значения, которое ввел пользователь. %2B - таким образом в URL (адресе) передается символ плюса.

Знак вопроса отделяет URL скрипта от GET-параметров.

Давайте поэкспериментируем с GET-параметрами.

Вместо phone=%2B79998887766 напишем test=мой текст и нажмем Enter.

-14

С одним параметром все ясно. Теперь разберемся, как передать больше параметров.

Параметры в URL друг от друга отделяются символом амперсанд - &.

Попробуем вот такой URL:

http://127.0.0.1/enterToClubFormHandler.php?test=мой текст&param2=параметр 2param3=параметр 3
-15

Вот именно таким образом на сервер передаются данные GET-запросом. То есть прямо в URL.

Поля формы тоже передаются параметром в запросе. Если будет больше 1 поля, то оно так и будет передано.

Обратите внимание, что данные, переданные в GET, в php на сервере хранятся в виде массива в переменной $_GET.

Передача данных POST-запросом

Итак, как передавать параметры запроса в адресной строке мы разобрались. Давайте теперь разберемся, как это делать не в адресной строке, а скрыто.

Для этого есть возможность передавать параметры не адресе, а в заголовке запроса.

Знакомьтесь с еще одним атрибутом тега form: атрибут method.

Он принимает всего 2 возможных значения: get или post. Собственно, от того, что выберите, данные формы будут передаваться либо одним способом, либо другим.

Кстати, если атрибут method не задан, то форма отправляет на сервер данные и так, и так: то есть сразу и post, и get.

Код формы должен стать таким:

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

Когда на сервер приходят данные с помощью POST, они сохраняются в php в массивом в переменной $_POST.

Поэтому в файле enterToClubFormHandler.php нам нужно изменить код $_GET на $_POST

print_r($_POST);

Теперь открываем заново главную страницу нашего сайта и заново отправляем форму.

По поводу возврата на предыдущую страницу стоит сказать пару слов:
Если вы жмете в браузере кнопку "Назад", то страница открывается в старой версии - она не загружается с веб-сервера заново. Поэтому, чтобы увидеть изменения в коде, ее нужно принудительно обновить.
Если вы открываете страницу не кнопками "назад-вперед" в браузере, то она должна прогрузиться с сервера заново. Но, если этого не произойдет, то попробуйте обновить страницу.
Бывает такая история, что страницу обновляешь, а код будто бы старый: старые стили, не отрабатывает новый код JS. Для этого нужно обновить страницу со сбросом кэша: на маке это CMD+Shift+R, на Windows это CTRL+F5.

Смотрим результат в браузере:

-16

Обратите внимание, что в адресной строке все чисто - поля формы были переданы в POST. А в массиве $_POST на сервере все появилось и отобразилось на экран.

Передача данных на сервер с помощью Ajax

Два способа сверху всем хороши кроме того, что браузер открывает страницу, обрабатывающую запрос, а не остается на той же странице, говорит что-то вроде "спасибо за ваш интерес".

Чтобы отправлять данные на сервер без перезагрузки страницы, придумали Ajax.

Вот здесь уже мы увидим более четкое разделение Frontend и Backend.

Чтобы отправить данные со страницы без перезагрузки, придется снова окунуться в Javascript - ведь код на стороне браузера пишется на нем.

А серверная часть на php уже примет наш запрос, обработает и выдаст браузеру ответ.

Ответ сервера обработает Javascript и сделает определенные действия, как мы напишем.

Поехали.

В index.php к тегу формы нужно присвоить ID. Назовем его joinToClubForm

<form action="joinToClubFormHandler.php" method="post" id="joinToClubForm">

И, чтобы быть точнее в английском языке, давайте в action поменяем enterToClubFormHandler.php на joinToClubFormHandler.php и сам php-скрипт переименуем в joinToClubFormHandler.php .

На стороне html все - больше ничего не нужно делать.

В JS нас ждут серьезные изменения. В самый конец файла modals.js пишем:

document.getElementById("joinToClubForm").addEventListener("submit",sendJoinToClubFormHandler);//Обработчик события отправки формы

function sendJoinToClubFormHandler (e) {//Функция обработки отправки формы
e.preventDefault();//Останавливаем действие по умолчанию, то есть отправку формы на сервер.

let request = new XMLHttpRequest();//Создаем объект для Ajax-запроса
request.open(this.method, this.action, true);//Инициализируем запрос

request.onreadystatechange = function() {//Пишем обработчик ответа сервера
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {//Если статус ответа сервера успешный, то выполнится код внутри фигурных скобок
console.log(this);
}
}

let data = new FormData(this);//Записываем в переменную data данные формы.

request.send(data);//Отправляем запрос на сервер
}

document.getElementById("joinToClubForm").addEventListener("submit",sendJoinToClubFormHandler);

Мы уже ранее перехватывали события на странице. Здесь все точно также: перехватываем событие submit для нашей формы. Это событие отправки формы. При событии submit дальнейшая работа будет отправлена функции sendJoinToClubFormHandler()

По событиям есть документация. Рекомендую ознакомиться детально:

https://www.w3schools.com/tags/ref_eventattributes.asp

function sendJoinToClubFormHandler (e) {

Функция, которую мы сделали для обработки события отправки формы. В нее передается аргумент e - это событие отправки формы.

e.preventDefault();

Первое действие, которое выполняется в нашей функции - отмена действий отправки формы по умолчанию. То есть не будет открываться страница joinToClubFormHandler.php - браузер на нее переключаться не будет.

Как это работает: e - это объект события, который мы приняли в функцию аргументом. Отправлен он был автоматически с addEventListener.

preventDefault() - метод, доступный в объекте event.

let request = new XMLHttpRequest();

Этим кодом мы создаем переменную request и в нее записываем новый объект класса XMLHttpRequest. Этот класс предоставляет нам функциональность обмена данными с сервером.

О работе с переменными, о классах мы поговорим на следующих уроках. На данный момент нужно знать, что переменная объявляется ключевым словом var или let, экземпляр класса создается ключевым словом new.

request.open(this.method, this.action, true);

Так мы инициализируем наш запрос. Или открываем его. При инициализации нужно указать:

  • метод передачи данных (POST),
  • url скрипта, на который будет отправлен запрос
  • и выбрать будет ли запрос выполняться синхронно или асинхронно.

Давайте теперь по порядку разбираться.

this

Это ключевое слово при работе с объектами. В нашем случае объект, с которым мы работаем - наша форма.

this.method

Хранит в себе значение атрибута method формы, а именно POST.

this.action

Хранит в себе значение атрибута action формы, а именно joinToClubFormHandler.php

Синхронно/асинхронно

Мы можем отправлять запрос на сервер синхронно: то есть отправили запрос, дождались, пока сервер обработал его, дал ответ и дальше мы уже продолжаем работу нашего JS-скрипта.

Можем отправлять асинхронно: то есть отправили запрос и работаем дальше, а когда сервер пришлет назад ответ, мы уже этот ответ обработаем.

true/false

Соответственно, если хотим асинхронно - пишем true, если синхронно - false. Мы хотим асинхронно.

request.onreadystatechange = function() {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { console.log(this);
}
}

Здесь мы описываем как раз обработчик ответа от сервера.

request - объект нашего запроса.

onreadystatechange - обработчик события, когда на сервере запрос обработается.

На это событие мы вешаем функцию, тело которой будет выполняться.

if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {

Условие, если текущее состояние ответа сервера (this.readyState) соответствует состоянию XMLHttpRequest.DONE и сервер вернул статус (this.status) 200 (200 - это успешная обработка, 500 - это ошибка сервера, 404 - это если страница не найдена. Кодов ответов много. Нас сейчас интересует либо успех 200, либо все остальное).

Если это условие соответствует действительности, то будет выполнен код внутри фигурных скобок.

console.log(this);

В консоль браузера будет возвращен объект, в котором вся информация о запросе. Мы узнаем, что ответил сервер.

let data = new FormData(this);

Создаем новую переменную data и записываем в нее данные, которые пользователь ввел в форму. Делаем это путем создания нового экземпляра класса FormData, в конструктор которого передаем аргумент this - это объект нашей формы.

Мы, когда будем подробнее разбираться с переменными, классами, областями видимости и контекстом, разберемся, что такое this и как оно работает. Важно понимать, что внутри функции sendJoinToClubFormHandler, которая была вызвана событием отправки формы, this - это объект формы, а события запроса request при ответе сервера, this - это объект запроса.

request.send(data);

Вызываем метод send() объекта request (наш запрос) и передаем ему в качестве аргумента переменную data - в ней хранятся данные с заполненной формы.

-17

Вот такой код получился.

Давайте теперь нашу страницу обновим в браузере со сбросом кэша (CTRL+F5 в Windows, CMD+Shift+R в Mac).

Теперь откроем инструменты разработчика (правая панель) и там откроем вкладку "Консоль".

-18

Настало время попробовать отправить форму и посмотреть на результат.

-19

Браузер отправил запрос, сервер его обработал и ответил нам. После чего отработал код console.log(this);, который вывел в консоль информацию об объекте запроса.

Слева от текста XMLHttpRequest есть треугольник - нажмите на него, чтобы развернуть информацию о запросе.

-20

Мы видим все свойства, которые есть у этого объекта. Например, там есть свойство response - это тело ответа сервера. То есть, чтобы вывести в консоль не весь объект запроса, а только ответ сервера, можно написать this.response. Давайте это и сделаем.

console.log(this); меняем на console.log(this.response);

Заново обновляем страницу со сбросом кэша (CTRL+F5 в Windows, CMD+Shift+R в Mac) и отправляем форму.

Смотрим результат в консоли.

-21

Это в точности то, что нам отвечал сервер, когда при отправке формы открывался php-скрипт обработки формы. А теперь мы не меняем страницу, а отправляем форму с помощью Ajax.

Отлично. С Ajax познакомились. Как отправлять данные с браузера на сервер посмотрели.

Скорее всего будут вопросы. Не стесняйтесь спрашивать в телеграм-группе:

SRMT22 Открытый клуб веб-разработки

Доработаем код на php

Давайте немного изменим код на PHP.

У нас есть массив $_POST - в нем хранятся данные, переданные скрипту с помощью POST.

В них есть "phone" - телефон из нашей формы.

print_r() просто выводит на экран все содержимое массива вместе с ключами и значениями.

То есть phone - это ключ, а номер телефона внутри - это значение.

Чтобы достать только phone, нужно написать $_POST["phone"].

Давайте заменим наш код joinToClubFormHandler.php на:

<?php
echo "Новый желающий вступить в клуб: ",$_POST["phone"];

Обновляем страницу со сбросом кэша и заново отправляем форму.

-22

Ура. На этом пока все. Дальше мы с этими данными сделаем 2 вещи: сохраним в базу данных и отправим уведомление в телеграм.

Для базы данных создадим новый контейнер mysql в докере.

А для телеграм создадим нового телеграм-бота.

Результат выполнения урока можно скачать здесь:

https://github.com/madmaker/srmt22-lsn15/archive/refs/tags/v1.zip

Резюме урока

Поздравляю, мы познакомились с тем, как отправлять данные из браузера на сервер и принимать ответы. Посмотрели, как работает POST, GET, как отправлять данные с помощью Ajax.

Посмотрели, как принимать данные от браузера на сервере с помощью php и как отвечать браузеру.

Всем спасибо!

Что делать дальше и как нам помочь?

1. Поставить лайк

2. Написать в комментарии, за сколько времени удалось сделать урок, с чем возникли сложности, что бы хотелось разобрать более детально

3. Подписаться на этот канал

4. Добавиться к нам в группу в наш открытый клуб веб-разработки в телеграм: https://t.me/srmt22_webclub

5. Сделать репост этого урока себе в соцсети.

Что будет на следующем занятии?

Создадим контейнер базы данных MySQL в Docker и разберемся, как записывать результаты заполнения формы о вступлении в клуб в базу данных.

Трудоустройство

Те, кто хочет индивидуальное обучение с преподавателем и быстрое гарантированное трудоустройство, пишите нам в телеграм:

Sarmatia 22