Весь современный веб построен на модели взаимодействия клиента и сервера. Как она работает:

  • браузер пользователя (клиент) отправляет на сервер запрос с адресом сайта (URL);
  • сервер получает запрос и отдаёт клиенту запрошенный контент.

Для реализации процесса используется универсальный протокол HTTP.

Как работает HTTP

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

👉🏼 Протокол HTTP очень прост и состоит из двух частей:

  • Заголовков запроса/ответа;
  • Тела запроса/ответа.

Сначала идёт список заголовков, затем пустая строка, после неё (если есть) тело запроса/ответа.

И клиент, и сервер могут посылать друг другу заголовки и тело ответа. У клиента доступные заголовки будут одни, у сервера — другие. Рассмотрим, как выглядит работа по протоколу HTTP, когда пользователь хочет загрузить главную страницу социальной сети «ВКонтакте».

  1. Браузер пользователя устанавливает соединение с сервером vk.com и отправляет следующий запрос:

    GET / HTTP/1.1
    Host: vk.com
    
    
  2. Сервер принимает запрос и отправляет ответ:

    HTTP/1.1 200 OK
    Server: Apache
    
    <html>
    <head>
      <title>ВКонтакте</title>
    </head>
    <!-- остальной контент страницы ниже -->
    
    
  3. Браузер принимает ответ и показывает готовую страницу.

Нам интересен самый первый шаг, где браузер инициирует запрос к серверу vk.com.

Здесь определяется несколько важных параметров:

  • Метод, которым будет запрошен контент;
  • Адрес страницы;
  • Версия протокола.

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

После метода идёт указание на адрес страницы — URI (универсальный идентификатор ресурса). Мы запрашиваем главную страницу сайта, поэтому используется просто слэш — /. В конце строки указана версия протокола, почти всегда это будет HTTP/1.1.

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

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

Сервер, получив запрос, ищет у себя сайт с доменом из заголовка Host, а также указанную страницу. Если запрошенный сайт и страница найдены, клиенту отправляется ответ:HTTP/1.1 200 OK. Такой ответ означает, что документ найден и будет отправлен клиенту.

👉 Общая структура стартовой строки ответа:

HTTP/Версия Код состояния Пояснение

Больше всего здесь интересен именно код состояния, он же код ответа сервера. В этом примере код ответа — 200, что означает: сервер работает, документ найден и будет передан клиенту.

Не всегда всё идёт гладко.

Например, запрошенный документ отсутствует или сервер перегружен. В таком случае клиент не получит контент, а код ответа будет отличным от 200.

  • 404 — если сервер доступен, но запрошенный документ не найден;
  • 503 — если сервер не может обрабатывать запросы по техническим причинам.

Спецификация HTTP 1.1 определяет 40 различных кодов HTTP.

После стартовой строки следуют заголовки, а затем тело ответа.

Работа с заголовками в PHP

В PHP есть все возможности для взаимодействия с HTTP:

  • Получение тела запроса;
  • Получение заголовков запроса;
  • Добавление/изменение заголовков ответа;
  • Управление телом ответа.

Разберём всё по порядку.

Получение тела запроса

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

В PHP-сценарии все данные отправленной формы будут доступны в специальном массиве $_POST. Более подробно об этом написано в следующей главе, посвящённой формам.

Получение заголовков запроса

Напомним ещё раз, что заголовки запроса — это метаинформация, отправленная браузером при запросе сценария.

PHP автоматически извлекает такие заголовки и помещает их в специальный массив — $_SERVER. Стоит отметить, что в этом массиве, помимо заголовков, есть и другая информация. Значения заголовков запроса находятся под ключами, которые начинаются с HTTP_. Подробно всё содержимое этого массива описано в официальной документации.

Пример, как получить предыдущую страницу, с которой перешёл пользователь:

print($_SERVER['HTTP_REFERER']);

Добавление/изменение заголовков ответа

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

  • Кэширование;
  • Переадресация пользователя;
  • Установка cookies;
  • Отправка файлов;
  • Передача дополнительной информации браузеру.

Заголовки ответа нужны для выполнения множества важных задач.

В PHP есть функция для отправки или смены заголовков: header().

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

Например, так выполняется перенаправление пользователя на другую страницу:

header("Location: /index.php");

За переадресацию отвечает заголовок с именем Location, а через двоеточие задаётся значение — адрес страницы для перехода.

Важное замечание по использованию заголовков

Есть одно ограничение: заголовки нельзя отправлять, если пользователю к этому моменту уже отправили любой контент. То есть если показать что-то на экране, например, через функцию print(), то после этого заголовки поменять уже не получится.

Управление телом ответа

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

Параметры запроса

Мы привыкли, что на нашем сайте каждый PHP-сценарий отвечает за одну страницу. Посетитель сайта вводит в адресную строку путь, который состоит из имени домена и имени PHP-сценария. Например, так: http://weather-diary.ru/day.php.

Но как быть, если одна страница должна показывать разную информацию?

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

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

Из чего состоит URI

URI — это уникальный идентификатор ресурса. Ресурс в нашем случае — это полный путь до страницы сайта. И вот как может выглядеть ресурс для показа погоды за конкретный день:

http://weather-diary.ru/day.php?date=2017-10-15

Разберём, из чего состоит этот URI.

Здесь есть имя домена: weather-diary.ru.

Затем идёт имя сценария: day.php.

А всё, что идёт после — это параметры запроса.

Параметры запроса — это как бы дополнительные атрибуты адреса страницы. Они отделяются от имени страницы знаком запроса. В примере выше параметр запроса только один: date=2017-10-30.

Имя этого параметра: date, значение: 2017-10-15.

Параметров запроса может быть несколько, тогда они разделяются знаком амперсанда: ?date=2017-10-15&tscale=celsius.

В примере выше указывается два аргумента: дата и единица измерения температуры.

Параметры запроса — как внешние переменные

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

Получение параметров запроса

Если есть внешние переменные, то как их прочитать?

Все параметры запроса находятся в специальном, ассоциативном массиве $_GET, а значит, сценарий, вызванный с таким адресом: day.php?date=2017-10-15&tscale=celsius будет иметь в этом массиве два значения с ключами date и scale.

Запрос на получение данных за выбранный день выглядит так:

<?php
$date = $_GET['date'] ?? date('Y-m-d');
$sql = sprintf('SELECT * FROM weather WHERE day = "%s"', mysqli_real_escape_string($con, $date));

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

Никогда не полагайтесь на существование параметра в массиве $_GET и делайте проверку либо функцией isset(), либо как в этом примере.

В этом задании вы сможете потренироваться использовать $_GET.

Формирование URI с параметрами запроса

Иногда нужно совершить обратную операцию: сформировать адрес страницы, включив туда нужные параметры запроса из массива.

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

Вот как это можно сделать:

<?php
$params = $_GET;
$date = $params['date'] ?? date('Y-m-d');

$tomorrow = date('Y-m-d', strtotime('tomorrow', strtotime($date)));
$params['date'] = $tomorrow;

$url = basename(__FILE__) . '/?' . http_build_query($params);
print($url);

Здесь мы использовали две функции:

  • basename(__FILE__) — получает имя текущего сценария;
  • http_build_query() — преобразует ассоциативный массив в строку запроса.

«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.

ТелеграмПодкастБесплатные учебники

Читать дальше

Как работает протокол HTTP

Как работает протокол HTTP

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

Читать дальше
  • 8 февраля 2023
Массивы в PHP

Массивы в PHP

Массив — это ещё один тип данных, вроде числа или строки. Главное отличие массива от остальных типов данных заключается в его способности хранить в переменной больше одного значения. В предыдущих примерах имя переменной всегда ассоциировалось только с одним значением:

  • $name = "Иннокентий"
  • $age = 42

А если мы хотим узнать не только пол, имя и возраст пользователя, но и, допустим, любимые сериалы? Очень непросто назвать один самый любимый сериал, а вот вспомнить несколько — намного легче. Сохранение в переменную-массив нескольких значений выглядит так:

 $fav_shows = ["game of thrones", "american horror story", "walking dead"];

В этом примере мы сохранили в переменной $fav_shows сразу три значения. Но сохранить эти данные — это только половина дела. Как с ними потом работать? Уже знакомый вам способ вывода переменной на экран не будет работать с массивами:

<?php
print("Мои любимые сериалы: " . $fav_shows);

Так увидеть список любимых сериалов не получится. Дело в том, что массив — это не обычная переменная. Массив хранит не простые типы, вроде текста или чисел (их ещё называют «скалярными типами»), а более сложную структуру данных, поэтому здесь нужен особый подход.

Внутри массива у каждого значения есть адрес, по которому к нему можно обратиться. Такой адрес называется индексом. Индекс — это просто порядковый номер значения внутри массива. Индексация начинается с нуля, так что первый элемент получает индекс — 0, второй — 1, и так далее.

Чтобы получить определенный элемент массива, необходимо знать его индекс (ключ). Напечатаем названия всех сериалов из массива через запятую:

<?php
print("Мои любимые сериалы: " . $fav_shows[0] . ", " . $fav_shows[1] . ", " . $fav_shows[2]);?>

Теперь можно дать определение массива: Массив — это совокупность множества элементов вида «ключ: значение».

Массивы позволяют перезаписывать существующие значения и добавлять новые. Добавить новое значение в массив можно так:

$fav_shows[] = "the big bang theory";

Новый элемент автоматически получит индекс равный максимальному индексу из существующих + 1. «Теория большого взрыва» сохранится в массиве под индексом 3.

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

$fav_shows[4] = "fargo";

Для полного удаления (без замены на другое) значения по его индексу существует функция unset:

unset($fav_shows[4]);
Читать дальше
  • 10 ноября 2022
Синтаксис PHP

Синтаксис PHP

Разберёмся, из чего состоит любой язык программирования.

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

Читать дальше
  • 27 октября 2022
Массивы $_POST и $_GET в PHP. Обработка форм

Массивы $_POST и $_GET в PHP. Обработка форм

Формы — это часть языка HTML. Формы нужны для передачи данных от клиента на сервер. Чаще всего формы используются для регистрации пользователей, заполнения анкет, оформления заказа в интернет магазине, и так далее.

Через формы можно отправлять как простую текстовую информацию, так и файлы.

Большую часть времени программирования на PHP вы будете так или иначе работать с формами и данными из них.

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

PHP содержит множество средств для работы с формами. Это позволяет очень просто решать типичные задачи, которые часто возникают в веб-программировании:

  • Регистрация и аутентификация пользователя;
  • Отправка комментариев на форумах и социальных сетях;
  • Оформление заказов.

Практически любой современный сайт содержит как минимум несколько разных HTML-форм.

Читать дальше
  • 20 октября 2022
Учебник по PHP

Учебник по PHP

  1. Знакомство с языком
  2. Шаблонизация и подключение файлов
  3. Протокол HTTP и формы
  4. Идентификация пользователя на сайте
  5. Базы данных
  6. Объекты и использование библиотек
  • 10 сентября 2022
Защита от SQL-инъекций

Защита от SQL-инъекций

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

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

Читать дальше
  • 10 сентября 2022
Объекты и классы в PHP

Объекты и классы в PHP

Объекты в PHP — это просто ещё один тип данных. Объект позволяет хранить в переменной набор из свойств и их значений, а также встроенные функции. Это делает объекты похожими по своей структуре на ассоциативные массивы. Но отличие от массивов всё-таки есть, и при этом достаточно важное — объекты могут иметь внутреннее состояние.

Читать дальше
  • 10 сентября 2022
Циклы в PHP. Краткое руководство

Циклы в PHP. Краткое руководство

Цикл — это конструкция языка, которая выполняет блок кода больше одного раза.

Мы привыкли, что сценарии выполняются линейно: сверху вниз, строчка за строчкой. Но что делать, если надо повторить какую-нибудь инструкцию несколько раз? Например, как вывести на экран натуральные числа от 1 до 9?

Есть очевидный способ:

<?php
print(1);
print(2);
print(3);
// и так далее...

Но он заставляет писать много кода. И что если требуется вывести последовательность из миллиона чисел? Ещё бывают ситуации, когда заранее неизвестно сколько раз нужно выполнить определённую инструкцию.

Использование циклов значительно упрощает и укорачивает код. Циклы незаменимы в ситуациях, когда заранее неизвестно сколько раз должен выполниться блок кода. Такое число зависит от множества условий и вычисляется в момент выполнения сценария.

Так выглядит цикл в PHP:

<?php
while (<условие цикла>) {
<тело цикла>
}
Читать дальше
  • 10 сентября 2022