Сегодняшнее занятие будет посвящено взаимодействию с пользователем и браузером пользователя. Будут рассмотрены механизмы персонализации сгенерированных PHP страниц, прием данных от пользователя, верстка и шаблонизация.
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-файл).
По окончанию обмена данными соединение разрывается, и следующее обращение к серверу происходит с чистого листа.
Под сессией подразумевается определенный контекст, в котором происходит обмен данными между клиентом (браузером) и сервером. В этом контексте хранится определенная информация, касающаяся только конкретного клиента (например залогиненного пользователя: логин, пароль, личная переписка и другая персональная информация). Как это работает:
POST /login/ HTTP/1.1
Host: example.com
Accept: text/html
login=user&password=eightasterisks
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 работает так же, как и протокол 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 является основным хранилищем данных сессии.
<?php
session_start();
if (!isset($_SESSION['counter'])){
$_SESSION['counter'] = 0;
}
$_SESSION['counter'] ++;
echo $_SESSION['counter'];
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;
?>
Развитие Web-технологий привело к тому, что HTTP отошел от изначальной идеи статических страниц с редкими динамическими вставками и пришел к большим динамическим проектам, в которых HTTP и HTML - не более чем способ реализации клиент-серверной архитектуры и отображения информации пользователю. Одной из основных парадигм, на которой строятся современные Web-приложения, является MVC - Model-View-Controller. Приложения разделяется на три слоя:
MVC относительно просто в понимании и реализации, что привело к тому, что подавляющее большинство современных Web-фреймворков строится именно на этом принципе.
MVC мы детально изучим на будущих занятиях; сегодня же мы рассмотрим шаблонизацию в контексте слоя View с помощью PHP и Twig
Сверстать шаблон страниц логина, успешного и неудавшегося входа:
$credentials = array( 'login' => 'foo',
'password' => 'bar');
Выше в ассоциативном массиве находятся поля для проверки.
Добавить к предыдущему заданию следующие возможности:
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