TemplateEngine.md 14 KB

Сессии, Куки, Формы и Шаблонизация

Сегодняшнее занятие будет посвящено взаимодействию с пользователем и браузером пользователя. Будут рассмотрены механизмы персонализации сгенерированных PHP страниц, прием данных от пользователя, верстка и шаблонизация.

Сессии и Куки

HTTP

HTTP - протокол, изначально предназначенный для работы в режиме запрос -> ответ, после чего соединение закрывается (вспомним о том, что изначально HTTP - просто средство выдачи страниц для чтения, не более того).

Например

Запрос:

GET / HTTP/1.1
Host: example.com
Accept: text/html
 

Ответ:

HTTP/1.1 200 OK
Content-Length: 1983
Content-Type: text/html; charset=utf-8
 
<html>
<head>...</head>
<body>...</body>
</html>

Таким образом, запрос и ответ состоят из стартовой строки(GET), заголовков (Content-Length), и собственно контента, ради которого весь этот обмен данных был сделан (html-файл).

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

Cookie

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

  • При создании сессии (например, при удачном логине) сервер создает уникальный ключ. Ключ должен быть достаточно большим, что бы его было крайне маловероятно подобрать.
POST /login/ HTTP/1.1
Host: example.com
Accept: text/html
 
login=user&password=eightasterisks
  • Ключ отсылается в браузер в заголовке вместе с ответом. Браузер запоминает его на определенное время для определенного URL
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Set-Cookie: key=LongAndWeirdRandomSecureCharset
 
<html>
<head>...</head>
<body>...</body>
</html>

Обратите внимание на заголовок Set-Cookie. Именно он в себе хранит уникальный ключ, который будет запомнен браузером

  • Браузер при каждом запросе к серверу отсылает ему этот ключ, подтверждая таким образом, что данное соединение - от конкретного пользователя.
GET / HTTP/1.1
Host: example.com
Accept: text/html
Cookie: key=LongAndWeirdRandomSecureCharset


PHP

Исторически сложилось, что PHP работает так же, как и протокол HTTP - скрипт запускается по запросу, отрабатывает, отдает ответ и умирает. Соответственно, сессия, как средство сохранения контекста между обращениями к скрипту, организуется в ручном режиме.

<?php
session_start();

Код выше осуществляет "старт" сессии - генерацию ключа и отправку его вместе с заголовком для текущего ответа. Сохраните этот код в файл и запустите встроенный в php web-сервер в папке с файлом

php -S 127.0.0.1:8000

Открыв в браузере ссылку http://127.0.0.1:8000/session.start.php и взглянув через Developer Tools на заголовки, вы увидите заголовок Set-Cookie в ответе сервера. После нажатия F5, и в дальнейшем браузер будет посылать заголовок Cookie подобного вида:

Cookie:PHPSESSID=5q8sgn2j1kj0jk4j5u8rldo5p1

PHPSESSID - имя для переменной сессии по умолчанию, можно настроить в php.ini параметром session.name

$_SESSION

Суперглобальный ассоциативный массив $_SESSION является основным хранилищем данных сессии.

<?php
session_start();
if (!isset($_SESSION['counter'])){
    $_SESSION['counter'] = 0;
}
$_SESSION['counter'] ++;
echo $_SESSION['counter'];

PHP Session API

Шаблонизация, PHP, MVC, и Формы

PHP изначально создавался как более продвинутый механизм для реализации SSI - Server Side Include, то есть вставка тех или иных динамических данных в статичный (по изначальной задумке) HTML. В старых версиях PHP синтаксис подобных вставок был более минималистичен и удобен, чем в современных версиях.

Исторический экскурс

Ниже приведены отличия между современным и старым синтаксисом PHP. Старый синтаксис на текущий момент выключен по умолчанию в конфигурации php.ini, однако его можно включить с помощью параметра short_open_tag

Было Стало
<? ?> <?php ?>
<?= $varname ?> <?php echo $varname; ?>

Шаблонно-ориентированные управляющие конструкции

Отыскивать парные фигурные скобки не очень удобно в коде с преобладанием HTML, поэтому PHP имеет не только обычный Си-образный синтаксис для if, while, for, foreach и switch. В каждом случае основной формой альтернативного синтаксиса является изменение открывающей фигурной скобки на двоеточие (:), а закрывающей скобки на endif;, endwhile;, endfor;, endforeach; или endswitch; соответственно.

<?php if ($a == 5): ?>
A равно 5
<?php endif; ?>

Альтернативный синтаксис также применяется и к else и elseif. Ниже приведена структура if с elseif и else в альтернативном формате:

<?php
if ($a == 5):
    echo "a равно 5";
    echo "...";
elseif ($a == 6):
    echo "a равно 6";
    echo "!!!";
else:
    echo "a не равно ни 5 ни 6";
endif;
?>

MVC

Развитие Web-технологий привело к тому, что HTTP отошел от изначальной идеи статических страниц с редкими динамическими вставками и пришел к большим динамическим проектам, в которых HTTP и HTML - не более чем способ реализации клиент-серверной архитектуры и отображения информации пользователю. Одной из основных парадигм, на которой строятся современные Web-приложения, является MVC - Model-View-Controller. Приложения разделяется на три слоя:

  • Model, слой доступа к СУБД или иному хранилищу данных, и логика работы с хранимыми данными
  • View, слой отображения. Именно эту роль в свое время занимал PHP и SSI, обычно на этом слое не происходит никаких сложных действий, не содержится бизнес-логики. Данный слой занимается просто вставкой нужных данных в HTML
  • Controller. На этом слое происходит обработка запросов от клиента, обращение к слою Модели, и, после получения данных, отправка их во View для отображения пользователю.

MVC относительно просто в понимании и реализации, что привело к тому, что подавляющее большинство современных Web-фреймворков строится именно на этом принципе.

MVC мы детально изучим на будущих занятиях; сегодня же мы рассмотрим шаблонизацию в контексте слоя View с помощью PHP и Twig

Задания

Задание 1: Форма, сессия, шаблонизация.

Сверстать шаблон страниц логина, успешного и неудавшегося входа:

  1. Пользователь видит форму с полями ввода логина и пароля;
  2. При отправке формы данные сверяются с конфигурацией в ассоциативном массиве;
  3. Если логин и пароль верны, то пользователь видит страницу с поздравлением и его логином. Факт успешного логина должен быть отмечен в сессии:
  4. Если логин и пароль неверны, пользователь должен получить страницу с ошибкой и его логином.
$credentials = array( 'login' => 'foo',
                 'password' => 'bar');

Выше в ассоциативном массиве находятся поля для проверки.

Задание 2: Циклическая генерация HTML в шаблоне

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

  1. Возможность сделать logout (разлогинится, выйти)
  2. При каждом логине запоминать время захода в сессии;
  3. Вывести историю заходов в форме таблицы

Выводы, PHP Hell

Twig

Twig - это обработчик шаблонов, который позволяет отделить логику (PHP-код) от представления (HTML, CSS, ...), сделанный идентично одному из самых продвинутых шаблонизаторов Jinja.

Установка

composer require twig/twig:1.*

Подключение

require_once '/path/to/vendor/autoload.php';

$loader = new Twig_Loader_Filesystem('/path/to/templates');
$twig = new Twig_Environment($loader, array(
    'cache' => '/path/to/compilation_cache',
    'auto_reload' => true, //автоматически перекомпилировать шаблон в кэше
));

echo $twig->render('index.tpl', array('url' => 'http://google.com',
                                  'urlText' => 'Гугл'));

или

require_once '/usr/share/php/Twig/Autoloader.php';
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem('templates/');
$twig = new Twig_Environment($loader, array(
            'cache' => '/tmp/',
            'auto_reload' => true, //автоматически перекомпилировать шаблон в кэше
            ));

echo $twig->render('index.tpl', array('url' => 'http://google.com',
			'urlText' => 'Гугл'));

Переменные

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

<html>
<a href="{{ url }}">{{ urlText }}</a>
</html>

Не имеет значения, как обращаться к полям ассоциативных массивов:

<html>
<a href="{{ url['href'] }}">{{ url.title }}</a>
</html>

Можно обратиться полю с помощью функции attribute:

{# equivalent to the non-working foo.data-foo #}
{# Комментарии заключаются в фигурную скобки и решетки #}
{{ attribute(foo, 'data-foo') }}

Управляющие конструкции

Управляющие конструкции заключаются в {% и %}:

<h2>Время логинoв:</h2>
<ul>
    {% for time in times %}
        <li>{{ time|date('d/m/Y H:i') }}</li>
    {% endfor %}
</ul>

В данном примере происходит циклический вывод массива врёмен логинов. date - фильтр, который используется для форматирования строки с датой и временем.

{% if not logged %}
    <div class='error'>Вы не залогинены!</div>
{% else %}
    <div class='info'>Добро пожаловать, {{ username }}!</div>
{% endif %}

Больше информации о Twig

Домашнее задание