1 of 32

Лекция 6:

Cookies и сессии �Разбор решения 3 ЛР

Структурирование проекта

intervolga.ru/school/

Ерофеев Анатолий Андреевич

ИНТЕРВОЛГА

Руководитель отдела разработки

2 of 32

Устройство ИНТЕРНЕТА,

HTTP, HTML, верстка

Веб-сервер�Лекции 1 и 2�ЛР 1

Работа с данными�PHP, MySQL, веб-формы, фильтрация данных�Лекции 3 и 4�ЛР 2

Работа с формами, куками, сессиями.

Авторизация, регистрация, проверка доступа�Лекции 5 и 6�ЛР 3

3 of 32

Вспоминаем “предысторию”

чтобы понять зачем нужны cookies и сессии

4 of 32

Краткая история WEB

  • 1955 — Железные локальные БД�
  • 1960 — Программные сетевые БД�
  • 1970 — Изобрели TCP и реляционные БД
  • 1973 — Интернет стал международным�
  • 1983 — Интернет через TCP�
  • 1990 — HTTP�
  • 1997 — PHP

5 of 32

В начале был Desktop

  • Разработка на компилируемых языках (C, C++, Pascal, ...)
  • Время работы приложения не ограничено
  • Нет лимитов по использованию CPU
  • 1 БД = 1 пользователь

6 of 32

Шло время

  • Появились многопользовательские программы:�1 БД + много пользователей�
  • Логин и пароль либо зашивались в программу,�либо хранились в файле настроек,�либо вводились при каждом запуске

Эта архитектура получила название “Толстый клиент”

Фатальный недостаток: бизнес-логика находилась в приложении.�Релиз = все должны переустановить приложение ручками

7 of 32

А в параллельной вселенной

Возникла сеть “Интернет”. Через эту сеть стала доступна передача файлов (в т.ч. HTML). Много HTML-файлов со ссылками назвали “сайтом”.

Однажды скучающий программист захотел вывести на такой статичной страничке текущее время. Он вклинился в процесс передачи файла и сделал простую замену маркера #TIME# в текстовом документе на текущее время.

Простой замены стало быстро не хватать. Так появился интерпретируемый язык PHP, который вставлялся прямо в тело файла и поддерживал циклы, условия и пр.

8 of 32

Слияние и поглощение

Потребность в выделении бизнес-логики из состава программ для ускорения доставки релизов и развитие сетей привели к появлению архитектуры “Тонкий клиент”.

Сама программа (или сайт) отвечали за отображение данных и передачу команд.

Бизнес-логика была вынесена в отдельную (единственную) копию на сервере приложений (или веб-сервере).

Использовались протоколы TCP и HTTP.

9 of 32

Коротко о протоколах

10 of 32

HTTP простой, но

HTTP — протокол передачи данных.

В отличие от TCP он не поддерживает длительных соединений и двустороннего общения.

Кратковременная память у рыб �~ 30 секунд.

Память вашего PHP-скрипта — “пока не закончится обработка текущего запроса”

11 of 32

Исправляем недостаток HTTP

HTTP — stateless протокол (без сохранения состояния).

А если нельзя, но очень хочется — можно придумать “workaround” (в просторечии “костыль”).

Так появились “сессии” и “куки”. Они работают в паре.

Нужны для идентификации посетителя и сохранения состояния на сервере.

12 of 32

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

Когда Вы отправляете форму, браузер отправляет запрос (через TCP-соединение в текстовом виде)

POST /web-integration/ HTTP/1.1

Host: www.intervolga.ru

Connection: keep-alive

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) ...

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

Referer: https://www.intervolga.ru/

Accept-Encoding: gzip, deflate, br

Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7,pt;q=0.6,fr;q=0.5,gl;q=0.4

Cookie: BITRIX_SM_IEC_CHK=N; PHPSESSID=3519da71f4d1cce93b8ace73df6fbdb0; _dc_gtm_UA-8490275-40=1

If-None-Match: 0cf856a7007ba5a233f9173a71d305e0

If-Modified-Since: Thu, 24 May 2018 10:35:59 GMT\n

\n

param1=12&param2=abcd

13 of 32

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

А затем читает из TCP-сокета ответ

Cache-Control: no-store, no-cache, must-revalidate�Connection: keep-alive�Content-Encoding: gzip�Content-Type: text/html; charset=UTF-8�Date: Thu, 24 May 2018 11:00:54 GMT�Expires: Thu, 19 Nov 1981 08:52:00 GMT�Server: nginx/1.12.1�Set-Cookie: LIVECHAT_HASH=e161bdd1a7ccad5b5b10ad58a36d44e4; expires=Fri, 24-May-2019 11:00:54 GMT; Max-Age=31536000; path=/�Set-Cookie: PHPSESSID=d9c66fe43c7e73356fb954a59d5b0e0d; path=/; HttpOnly�Transfer-Encoding: chunked�X-Powered-By: PHP/7.0.21�X-UA-Compatible: IE=Edge,chrome=1\n

\n

<!DOCTYPE html>�<html lang="ru">�<head>� <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">�<meta name="description" content="решение задач развивающегося бизнеса">

...

14 of 32

Cookie

Cookie — почти двухуровневый словарь (второй уровень слит в 1 строку)

{

key1: {value: value1, expires: DD.MM.YYYY, url: /, ...},

key2: {...},

}

С каждым HTTP-запросом браузер передает куки

  • текущего домена
  • текущей страницы и всех более глубоких

Ни сервер ни JavaScript не могут узнать куки чужого домена.

JavaScript не может видеть куки с флагом HTTP Only

15 of 32

Сессии

Сессии — одноуровневые словари.

Хранятся в файлах или таблице БД.

Идентифицируются длинным GUID.

16 of 32

Сессии и cookies

Когда приложению (PHP) необходимо поработать с “состоянием” посетителя, он

  • или создает новую сессию и отправляет ее имя обратно в cookie “SESSID”,
  • или открывает существующую зная SESSID из cookies запроса.

Далее приложение записывает/читает данные из сессии (словаря).

Например, при авторизации в сессию записывается ID пользователя и возможно IP (безопасность).

При закрытии сессии она сохраняется в файл (с именем SESSID) или БД с ключом SESSID.

17 of 32

Лабораторная работа “Регистрация и авторизация”

18 of 32

Правильная структура

С каждой следующей ЛР поддерживать ваш проект будет все больше, а его поддержка все сложнее…

… если не принять мер.

19 of 32

Правильная структура PHP-скрипта

20 of 32

Подключение к БД: драйвер

mysqli

  • быстрый
  • для защиты от инъекций нужно использовать mysql_real_escape_string()

PDO

  • универсальный (много поддерживаемых БД)
  • для защиты от инъекций нужно использовать метод bindValue() у подготовленного выражения

21 of 32

Подключение к БД: как хранить

Глобальная переменная

  • просто в реализации
  • сильно затрудняет функциональное тестирование
  • считается антипаттерном

Singleton

  • гарантирует наличие только 1 экземпляра
  • ленивая инициализация
  • нарушает принцип единственной ответственности
  • содержит скрытые зависимости

Вопрос аудитории: кто знает решение лучше?

22 of 32

Подключение к БД: Singleton + PDO

23 of 32

Старт сессии

  • session_start() можно вызывать сколько угодно раз без вреда, но это считается плохой практикой
  • обычно сессию стартуют где-то рядом с подключением к БД
  • одновременные запросы при наличие сессии будут вставать в очередь (эксклюзивная блокировка), но обычно это приемлемо

24 of 32

Правильная структура: данные

Существуют 3 “паттерна” работы с данными:

  • Transaction script
  • Table module ← для ЛР рекомендую этот
  • Domain driven design

25 of 32

TableModule

26 of 32

Правильная структура: логика

Высокоуровневые операции над сущностями (регистрация, авторизация и т.д.) рекомендуется отделять от данных и представления.

Здесь старайтесь не использовать $_POST и прочие данные полученные напрямую от пользователя (все брать из аргументов метода)

27 of 32

Правильная структура: действия

Rule of thumb: Любые действия, меняющие состояние сервера или БД должны инициироваться POST-запросом.

Обработку таких действий также желательно группировать по сущностям

28 of 32

Правильная структура: ядро

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

29 of 32

Правильная структура: ядро

В местах, где Вам нужен доступ к “ядру” — просто подключите его.

30 of 32

Правильная структура: шапка и подвал

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

31 of 32

Не допускайте ошибок

  • Сессия нужна, чтобы хранить данные о текущем пользователе между хитами (запросами).�Идеологически сессию НЕПРАВИЛЬНО использовать для:
    • хранения данные из текущей обрабатываемой формы,
    • передачи данных между подключаемыми скриптами,
    • хранения сообщений об ошибках
  • Когда пользователь отправляет форму и действие не удалось (ошибка валидации и т.д.) нужно показать ему и ошибки и заполненные им значения полей.�Данные при этом нужно брать из $_POST, но при выводе в html делать их безопасными (htmlspecialchars)
  • Помните, что пользователь может заполнять одну и ту же форму в разных вкладках и даже браузерах.

32 of 32

Задавайте вопросы.

Ерофеев Анатолий Андреевич

руководитель отдела разработки ИНТЕРВОЛГА