Самые основы. Как работает PHP. Создание html страниц с помощью PHP Создать страницу на php

Многие читатели в любой книге о компьютерах пролистывают все, что не представляет непосредственного интереса, и переходят к тому, что они действительно хотят знать. Лично я поступаю именно так. Впрочем, в этом нет ничего страшного -- редко встречаются технические книги, которые необходимо читать от корки до корки. А может, вы именно так и поступили -- пропустили восемь начальных глав и взялись за эту главу, потому что у нее было самое интересное название? Да и кому захочется тратить время на подробности, когда на работе «горит» очередной проект?

К счастью, подобная торопливость не помешает вам нормально усвоить материал второй части книги, посвященной использованию PHP для построения сайтов и взаимодействия с Web. В этой главе вы научитесь легко модифицировать содержимое web-страниц и осуществлять навигацию в Web при помощи ссылок и различных стандартных функций. Следующая глава дополнит изложенный материал - в ней подробно рассматриваются средства взаимодействия с пользователем в формах HTML В главе 11 описана организация интерфейса с базами данных. В остальных главах второй части рассматриваются нетривиальные аспекты web-программирования на PHP.

Однако следует помнить о том, что материал части 1 абсолютно необходим для нормального владения PHP. Предполагается, что вы все же прочитали первую часть, поэтому в примерах будут использоваться многие из описанных ранее концепций. Итак, если вы пролистали часть книги, вам придется время от времени возвращаться к предыдущим главам и наверстывать упущенное.

Простые ссылки

<а href = "date.php">

$link = "date.php";

print "<а href = \"$link\">View today"s date
\n"

Вероятно, у вас возник вопрос -- почему в коде ссылки перед кавычками (") ставится обратная косая черта (\)? Дело в том, что кавычки в PHP являются специальными символами и используются в качестве ограничителей строк. Следовательно, кавычки-литералы в строках должны экранироваться.

Если необходимость экранировать кавычки вас раздражает, просто включите режим magic_quotes_gpc в файле php.ini. В результате все апострофы, кавычки, обратные косые черты и нуль-символы. в тексте автоматически экранируются!

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

// Создать массив разделов

$contents - array("tutorials", "articles", "scripts", "contact");

// Перебрать и последовательно вывести каждый элемент массива

for ($i = 0; $i < sizeof($contents; $i++)

print " • ".$contents[$i]."
\n";

// • - специальное обозначение точки-маркера endfor;

Файловые компоненты (шаблоны)

Мы подошли к одной из моих любимых возможностей PHP. Шаблоном (применительно к web-программированию) называется часть web-документа, которую вы собираетесь использовать в нескольких страницах. Шаблоны, как и функции PHP, избавляют вас от лишнего копирования/вставки фрагментов содержания страницы и программного кода. С увеличением масштабов сайта значение шаблонов возрастает, поскольку они позволяют легко и быстро проводить модификации на уровне целого сайта. В этом разделе будут описаны некоторые возможности, которые открываются при использовании простейших шаблонов.

Как правило, общие фрагменты содержания/кода (то есть шаблоны) сохраняются в отдельных файлах. При построении web-документа вы просто «включаете» эти файлы в соответствующие места страницы. В PHP для этого существуют две функции: include() и require().

include() и require()

Одним из самых выдающихся аспектов PHP является возможность построения шаблонов и программных библиотек и их последующей вставки в новые сценарии. Применение библиотек экономит время и усилия по использованию общих функциональных возможностей на разных web-сайтах. Читатели, обладающие

опытом программирования на других языках (например, С, C++ или Java), хорошо знакомы с концепцией библиотек функций и их использованием в программах для расширения функциональных возможностей.

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

Функции

В PHP существуют четыре функции для включения файлов в сценарии PHP:

  • include();
  • include_once();
  • require();
  • require_once().

Несмотря на сходство имен, эти функции решают разные задачи.

Функция include() включает содержимое файла в сценарий. Синтаксис функции include():

include (file файл]

У функции include() есть одна интересная особенность -- ее можно выполнять условно. Например, если вызов функции включен в блок команды if. то файл включается в программу лишь в том случае, если условие i f истинно. Если функция includeO используется в условной команде, то она должна быть заключена в фигурные скобки или в альтернативные ограничители. Сравните различия в синтаксисе листингов 9.1 и 9.2.

Листинг 9.1. Неправильное использование include()

if (some_conditional)

include ("text91a.txt"); else

include ("text91b.txt");

Листинг 9.2. Правильное использование include()

if (some_conditional) :

include ("text91a.txt");

include ("text91b.txt");

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

Вместо этого необходимо заключить команду в соответствующие теги, как показывает следующий пример:

print "this is an invalid include file";

Функция include_once() делает то же, что и include(), за одним исключением: прежде чем включать файл в программу, она проверяет, не был ли он включен ранее. Если файл уже был включен, вызов include_once() игнорируется, а если нет -- происходит стандартное включение файла. Во всем остальном include_once() ничем не отличается от include(). Синтаксис функции include_once():

include_once (file файл)

В целом функция require() похожа на include() -- она тоже включает шаблон в тот файл, в котором находится вызов require(). Синтаксис функции require():

require (file файл)

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

Во многих ситуациях бывает удобно создать файл с переменными и другой информацией, которая используется в масштабах сайта, и затем подключать его по мере необходимости. Хотя имя этого файла выбирается произвольно, я обычно называю его init.tpl (сокращение от «initializaion.template»). В листинге 9.3 показано, как выглядит очень простой файл init.tpl. В листинге 9.4 содержимое init.tpl включается в сценарий командой require().

Листинг 9.3. Пример инициализационного файла

$site_title = "PHP Recipes";

$contact_email = "[email protected]";

$contact_name = "WJ Gilmore";

Листинг 9.4. Использование файла init.tpl

<? print $site_title; ?>

\"mai1 to:$contact_email\">$contact_name."; ?>

Передача URL при вызове require() допускается лишь при включенном режиме «URL fopen wrappers» (этот режим включен по умолчанию).

С увеличением размеров сайта может оказаться, что некоторые файлы включаются в сценарий по несколько раз. Иногда это не вызывает проблем, но в некоторых случаях повторное включение файла приводит к сбросу значений изменившихся переменных. Если во включаемом файле определяются функции, могут возникнуть конфликты имен. Учитывая сказанное, мы приходим к следующей функции -- require_once().

Функция require_once() гарантирует, что файл будет включаться в сценарий всего один раз. После вызова requi rе_оnсе() все дальнейшие попытки включения того же файла игнорируются. Синтаксис функции requiге_оnсе():

Вероятно, вы станете чаще использовать функции включения файлов по мере того, как ваши web-приложения начнут увеличиваться в размерах. Эти функции часто встречаются в примерах данной книги, чтобы сократить избыточность программного кода. Первые примеры рассматриваются в следующем разделе, посвященном принципам построения базовых шаблонов.

Построение компонентов

При определении структуры типичной web-страницы я обычно разбиваю ее на три части: заголовок, основную часть и колонтитул. Как правило, в большинстве правильно организованных web-сайтов присутствует заголовок, который практически не изменяется; в основной части выводится запрашиваемое содержание сайта, поэтому она часто изменяется; наконец, колонтитул содержит информацию об авторских правах и навигационные ссылки. Колонтитул, как и заголовок, обычно остается неизменным. Не поймите меня превратно -- я вовсе не пытаюсь подавлять ваши творческие устремления. Мне встречалось немало великолепных сайтов, не следовавших этим принципам. Я всего лишь пытаюсь выработать общую структуру, которая может послужить отправной точкой для дальнейшей работы.

Заголовок

Заголовочный файл (вроде приведенного в листинге 9.5) присутствует практически в каждом из моих web-сайтов с поддержкой PHP. В этом файле содержится

информация, действующая на уровне всего сайта, -- например, заголовок, контактные данные и некоторые компоненты кода HTML-страницы.

Листинг 9.5. Пример файла заголовка

// Файл: header.tpl

// Назначение: заголовочный файл для сайта PhpRecipes .

$site_name = "PHPRecipes";

$site_email= "[email protected]";

$site_path = "http://localhost/phprecipes";

<? print $site_name; ?>

// Вывести текущую дату и время

print date ("F d, h:i a");

Довольно часто доступ к включаемым файлам со стороны посетителей ограничивается, особенно если эти файлы содержат конфиденциальную информацию (например, пароли). В Apache можно запретить просмотр некоторых файлов редактированием файлов http.conf или htaccess. Следующий пример показывает, как запретить просмотр всех файлов с расширением.tpl:

Order allow,deny

Allow from 127.0.0.1

PHP и проблемы безопасности сайтов подробно описаны в главе 16.

Колонтитул

Колонтитулом (footer) обычно называется информация, расположенная в нижней части страниц сайта, -- контактные данные, ссылки и информация об авторских правах. Эту информацию можно разместить в отдельном файле и включать в качестве шаблона так же, как это делается с заголовком. Допустим, c наступлением нового года вам потребовалось изменить информацию об авторских правах и привести ее к виду «Copyright © 2000-2001». Есть два пути: потратить канун Рождества на лихорадочное редактирование сотен статических страниц или воспользоваться шаблоном наподобие приведенного в листинге 9.6. Одно простое изменение -- и вы можете возвращаться к праздничным хлопотам.

Листинг 9.6. Пример файла колонтитула (footer.tpl)

contact |

your privacy

Обратите внимание на использование глобальной переменной $site_email в файле колонтитула. Значение этой переменной действует в масштабах всей страницы, а мы предполагаем, что файлы header.tpl и footer.tpl будут включены в одну итоговую страницу. Также обратите внимание на присутствие пути $site_path в ссылке Privacy (Конфиденциальность). Я всегда включаю в шаблоны полные пути ко всем ссылкам -- если бы URL ссылки состоял из одного имени privacy.php, то файл колонтитула был бы жестко привязан к конкретному каталогу.

Основная часть

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

Листинг 9.7. Пример основной части страницы (index_body.tpl)

/tutorials.php">tutorials

articles

scripts

contact

Welcome to PHPRecipes. the starting place for PHP scripts, tutorials,

and information about gourmet cooking!

Все вместе: заголовок, колонтитул и основная часть

Вероятно, мое настроение лучше всего выражается фразой полковника «Ганнибала» Смита (Джордж Пеппард) из знаменитого сериала «Команда А»: «Люблю, когда все становится на свои места». Я испытываю нечто подобное, когда разрозненные шаблоны объединяются и образуют полный web-документ. Комбинируя три секции документа: header.tpl, index_body.tpl и footer.tpl, -- можно быстро построить простейшую страницу вроде той, что приведена в листинге 9.8.

Листинг 9.8. Построение страницы index.php включением нескольких файлов

// Файл: index.php

// Назначение: домашняястраница PHPRecipes

// Вывести заголовок

include ("header.tpl");

// Вывести основную часть

include ("index_body.tpl");

// Вывести колонтитул

include ("footer.tpl");

Ну как? Три простые команды -- и перед вами готовая страница. Текст итоговой страницы приведен в листинге 9.9.

Листинг 9.9. Страница HTML, построенная в листинге 9.8 (index.php)

PHPRecipes

August 23, 03:17 pm

tutorials

articles

scripts

contact

Welcome to PHPRecipes, the starting place for PHP scripts, tutorials,

and gourmet cooking tips and recipes!

Copyright 2000 PHPRecipes. All rights reserved.

contact |

your privacy

На рис. 9.1 показано, как полученная страница выглядит в браузере. Хотя я обычно не пользуюсь рамками таблиц, на этот раз я их вывел, чтобы на рисунке более наглядно выделялись три части страницы.

Рис. 9.1. Внешний вид страницы, построенной в листинге 9.8

Оптимизация шаблонов

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

Листинг 9.10. Оптимизированный шаблон сайта (site_init.tpl)

// Файл: site_init.tpl

// Назначение: инициализационный файл PhpRecipes

$site_name = "PHPRecipes";

$site_email = "[email protected]";

$site_path = "http://localhost/phprecipes/";

function show_header($site_name) {

<? print $site_name: ?>

This is the header

function show footer ()

This Is the footer

Листинг 9.11. Применение инициализационного файла

// Включить инициализационный файл

include("site_init.tpl");

// Вывести заголовок

show header ($site_name);

// Содержимое основной части This is some body information

// Вывести колонтитул Show_footer();

Проект: генератор страниц

Хотя в большинстве созданных мною web-сайтов основное содержимое страниц формировалось на основании информации, прочитанной из базы данных, всегда найдется несколько страниц, которые практически не изменяются. В частности, на них могут выводиться сведения о команде разработчиков, контактные данные, реклама и т. д. Я обычно храню эту «статическую» информацию в отдельной папке и использую сценарий PHP для ее загрузки при поступлении запроса. Конечно, у вас возникает вопрос -- если это статическая информация, для чего нужен сценарий PHP? Почему бы не загружать обычные страницы HTML? Преимущество PHP заключается в том, что вы можете использовать шаблоны и вставлять статические фрагменты по мере необходимости.

<а href = "/static.php?content=$content">Static Page Name

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

Листинг 9.12. Информация о сайте (about.html)

About PHPRecipes

What programmer doesn"t mix all night programming with gourmet cookies. Here at PHPRecipes. hardly a night goes by without one of our coders mixing a little bit of HTML with a tasty plate of Portobello Mushrooms or even Fondue. So we decided to bring you the best of what we love most: PHP and food!

That"s right, readers. Tutorials, scripts, souffles and more. 0nly at PHPRecipes.

Advertising Information

Regardless of whether they come to learn the latest PHP techniques or for brushing up on how

to bake chicken, you can bet our readers are decision makers. They are the Industry

professionals who make decisions about what their company purchases.

For advertising information, contact

">[email protected].

Листинг 9.14. Контактные данные (contact.html)

Contact Us

Have a coding tip?

Know the perfect topping for candied yams?

Let us know! Contact the team at [email protected].

Переходим к построению страницы static.php, которая выводит запрашиваемую статическую информацию. В этот файл (см. листинг 9.15) включаются компоненты страниц нашего сайта и инициализационный файл site_init.tpl.

Листинг 9.15. Общий вывод статических страниц (static.php)

// Файл: static.php

// Назначение: отображение запрашиваемых статических страниц.

// ВНИМАНИЕ: предполагается, что файл "site_init.tpl" и все

// статические файлы находятся в том же каталоге.

// Загрузить функции и переменные include("site_init.tpl"):

// Вывести заголовок show_header($site_name);

// Вывести запрашиваемое содержание include("$content.html"):

// Вывести колонтитул show footer();

Теперь все готово к построению основного сценария. Просто включите в страницу

<а href = "static.php?content=about">Static Page Name

Advertising Information

Contact Us

Если щелкнуть на любой из этих ссылок, в браузере загружается соответствующая статическая страница, внедренная в static.php!

Итоги

В этой главе вы познакомились с первоочередной задачей, для решения которой и создавался PHP, -- динамическим построением web-страниц. Были рассмотрены следующие вопросы:

  • обработка URL;
  • построение динамического содержания;
  • включение и построение базовых шаблонов.

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

Следующая глава посвящена использованию PHP в сочетании с формами HTML, заметно повышающими степень интерактивности вашего сайта. А потом -- взаимодействие с базами данных! Вам предстоит узнать много интересного.

Если вы только что столкнулись с PHP, то вам нужно знать некоторые определения.
Прежде всего, PHP – это язык программирования и служит он для написания команд (сценариев), адресованных серверу. Если говорить ещё проще, то при помощи PHP мы можем общаться с сервером.
Команды PHP легко внедряются в HTML страницы. Именно это свойство является важным преимуществом языка PHP перед такими языками, как Perl и C.

Синтаксис PHP

PHP код сценария начинается после открывающего тэга . Текст между этими двумя тэгами считывается программой , находящейся на сервере, а в HTML-документ выводится полученный результат. Рассмотрим на примере:



Пример

include ("sidebar.htm") ;
?>


Если нам нужно что-то вставить в html код страницы необходимо использовать команду include (вставить). Далее указываем адрес файла, а заканчивается строка, как и в CSS ;

Вставляем HTML код в страницы сайта

Как правило боковые колонки (sidebar ) и подвал (footer ) остаются неизменными на всех страницах сайта. Следовательно коды

.....
и можно вынести в отдельные htm страницы "sidebar.htm" и "footer.htm" и вставлять в страницы сайта при помощи команды include . Если при этом вынести в отдельный файл и главное содержимое -
.....
, то код нашей страницы будет иметь вид:



Пример

include ("sidebar.htm") ;
include ("content.htm") ;
include ("footer.htm") ;
?>


содержимое sidebar.htm


здесь
содержимое
Вашего
сайд-бара

Аналогично с файлами content.htm и footer.htm .

При такой генерации страниц Вам достаточно внести изменения в один файл "sidebar.htm" , что бы изменились все страницы сайта. Что очень удобно если Ваш сайт состоит из сотни или тысячи страниц.

PHP на Вашем компьютере

Чтобы Вы могли работать с PHP-скриптами и просматривать результаты выполнения в браузере, вам нужно установить работающий веб сервер с PHP на Вашем локальном компьютере.
Лучше всего для таких задач подойдёт Денвер . (официальный сайт предоставляет всё необходимое бесплатно ) В комплект установки входит - Apache, php и MySQL. Другими словами на Вашем компьютере будет находиться полнофункциональный сервер для хостинга сайтов .

Для того, что бы PHP код работал в HTML страницах необходимо открыть файл .htaccess в любом текстовом редакторе и прописать следующее:

AddHandler application/x-httpd-php .html

Данная запись разрешает выполнение PHP скриптов в HTML страницах.

Или изменить расширение файла.html на.php

Возможности PHP

PHP способен не только выдавать HTML. Возможности PHP включают формирование изображений, файлов PDF и даже роликов Flash (с использованием libswf и Ming), создаваемых "на лету". PHP также способен выдавать любые текстовые данные, такие, как XHTML и другие XML-файлы. PHP способен осуществлять автоматическую генерацию таких файлов и сохранять их в файловой системе вашего сервера, вместо того, чтобы отдавать клиенту, организуя, таким образом, кеш динамического содержания, расположенный на стороне сервера.

Одним из значительных преимуществ PHP является поддержка широкого круга баз данных. Словом, PHP может предложить вам очень многое! Подробно о преимуществах PHP можно ознакомиться на www.php.su .

February 1, 2015

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

Что нужно знать

    Также нужно знать как записывается PHP. В файле, PHP скрипт начинается со слова - и заканчивается на ?> . Все, что между и ?> это PHP код, запомните это.

    Файлы, в котором записан PHP код нужно сохранять под расширением .php

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

Программное обеспечение

    Первая программа, которая вам нужна, это браузер (то, в чем Вы сейчас находитесь:D)

    Веб-сервер. Для локального тестирования вам нужно установить веб-сервер. Я рекомендую поставить Open Server (Mini версии будет достаточно). Как установить Open Server . Open Server является портативным, т.е. вам нужно только разархивировать скачанный архив и запустить сервер через Open Server.exe . После старта программы вы увидите красный флажок в трее Windows (область возле системных часов). Чтобы включить непосредственно сам веб-сервер нажмите на флажок, далее выберите пункт меню Запустить.

Create a file named hello.php and put it in your web server"s root directory (DOCUMENT_ROOT) with the following content:

Example #1 Our first PHP script: hello.php



PHP Test


Hello World

" ; ?>

Use your browser to access the file with your web server"s URL, ending with the /hello.php file reference. When developing locally this URL will be something like http://localhost/hello.php or http://127.0.0.1/hello.php but this depends on the web server"s configuration. If everything is configured correctly, this file will be parsed by PHP and the following output will be sent to your browser:

PHP Test

Hello World

This program is extremely simple and you really did not need to use PHP to create a page like this. All it does is display: Hello World using the PHP echo statement. Note that the file does not need to be executable or special in any way. The server finds out that this file needs to be interpreted by PHP because you used the ".php" extension, which the server is configured to pass on to PHP. Think of this as a normal HTML file which happens to have a set of special tags available to you that do a lot of interesting things.

If you tried this example and it did not output anything, it prompted for download, or you see the whole file as text, chances are that the server you are on does not have PHP enabled, or is not configured properly. Ask your administrator to enable it for you using the Installation chapter of the manual. If you are developing locally, also read the installation chapter to make sure everything is configured properly. Make sure that you access the file via http with the server providing you the output. If you just call up the file from your file system, then it will not be parsed by PHP. If the problems persist anyway, do not hesitate to use one of the many options.

The point of the example is to show the special PHP tag format. In this example we used to indicate the start of a PHP tag. Then we put the PHP statement and left PHP mode by adding the closing tag, ?> . You may jump in and out of PHP mode in an HTML file like this anywhere you want. For more details, read the manual section on the basic PHP syntax .

Note : A Note on Line Feeds

Line feeds have little meaning in HTML, however it is still a good idea to make your HTML look nice and clean by putting line feeds in. A linefeed that follows immediately after a closing ?> will be removed by PHP. This can be extremely useful when you are putting in many blocks of PHP or include files containing PHP that aren"t supposed to output anything. At the same time it can be a bit confusing. You can put a space after the closing ?> to force a space and a line feed to be output, or you can put an explicit line feed in the last echo/print from within your PHP block.

Note : A Note on Text Editors

There are many text editors and Integrated Development Environments (IDEs) that you can use to create, edit and manage PHP files. A partial list of these tools is maintained at » PHP Editors List . If you wish to recommend an editor, please visit the above page and ask the page maintainer to add the editor to the list. Having an editor with syntax highlighting can be helpful.

Note : A Note on Word Processors

Word processors such as StarOffice Writer, Microsoft Word and Abiword are not optimal for editing PHP files. If you wish to use one for this test script, you must ensure that you save the file as plain text or PHP will not be able to read and execute the script.

Note : A Note on Windows Notepad

If you are writing your PHP scripts using Windows Notepad, you will need to ensure that your files are saved with the .php extension. (Notepad adds a .txt extension to files automatically unless you take one of the following steps to prevent it.) When you save the file and are prompted to provide a name for the file, place the filename in quotes (i.e. " hello.php "). Alternatively, you can click on the "Text Documents" drop-down menu in the "Save" dialog box and change the setting to "All Files". You can then enter your filename without quotes.

Now that you have successfully created a working PHP script, it is time to create the most famous PHP script! Make a call to the phpinfo() function and you will see a lot of useful information about your system and setup such as available predefined variables , loaded PHP modules, and configuration settings. Take some time and review this important information.

Example #2 Get system information from PHP

Всем хорошего дня. Перед вами первая статья из серии PHP для начинающих разработчиков. Это будет необычная серия статей, тут не будет echo "Hello World" , тут будет hardcore из жизни PHP программистов с небольшой примесью “домашней работы” для закрепления материала.

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

Но для начала, чтобы понять зачем нам сессия, обратимся к истокам – к HTTP протоколу.

HTTP Protocol

HTTP протокол – это HyperText Transfer Protocol - «протокол передачи гипертекста» – т.е. по сути – текстовый протокол, и его понять не составит труда.

Изначально подразумевали, что по этому протоколу будет только HTML передаваться, отсель и название, а сейчас чего только не отправляют( _ㅅ_ )=^.^=

Чтобы не ходить вокруг да около, давайте я вам приведу пример общения по HTTP протоколу, вот запрос, каким его отправляет ваш браузер, когда вы запрашиваете страницу http://example.com:

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 ... ...

Это очень упрощенные примеры, но и тут можно увидеть из чего состоят HTTP запрос и ответ:

  1. стартовая строка – для запроса содержит метод и путь запрашиваемой страницы, для ответа – версию протокола и код ответа
  2. заголовки – имеют формат ключ-значение разделенные двоеточием, каждый новый заголовок пишется с новой строки
  3. тело сообщения – непосредственно HTML либо данные отделяют от заголовков двумя переносами строки, могут отсутствовать, как в приведенном запросе

Так, вроде с протоколом разобрались – он простой, ведёт свою историю аж с 1992-го года, так что идеальным его не назовешь, но какой есть – отправили запрос – получите ответ, и всё, сервер и клиент никоим образом более не связаны. Но подобный сценарий отнюдь не единственный возможный, у нас же может быть авторизация, сервер должен каким-то образом понимать, что вот этот запрос пришёл от определенного пользователя, т.е. клиент и сервер должны общаться в рамках некой сессии. И да, для этого придумали следующий механизм:

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

Для реализации этого механизма и были созданы (куки, печеньки) – простые текстовые файлы на вашем компьютере, по файлу для каждого домена (хотя некоторые браузеры более продвинутые, и используют для хранения SQLite базу данных), при этом браузер накладывает ограничение на количество записей и размер хранимых данных (для большинства браузеров это 4096 байт, см. RFC 2109 от 1997-го года)

Т.е. если украсть cookie из вашего браузера, то можно будет зайти на вашу страничку в facebook от вашего имени? Не пугайтесь, так сделать нельзя, по крайней мере с facebook, и дальше я вас научу как можно защититься от данного вида атаки на ваших пользователей.

Давайте теперь посмотрим как изменятся наши запрос-ответ, будь там авторизация:

POST /login/ HTTP/1.1 Host: example.com Accept: text/html login=Username&password=Userpass

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

HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Set-Cookie: KEY=VerySecretUniqueKey ... ...

Ответ сервер будет содержать заголовок Set-Cookie: KEY=VerySecretUniqueKey , что заставит браузер сохранить эти данные в файлы cookie, и при следующем обращении к серверу – они будут отправлены и опознаны сервером:

GET / HTTP/1.1 Host: example.com Accept: text/html Cookie: KEY=VerySecretUniqueKey ...пустая строка...

Как можно заметить, заголовки отправляемые браузером (Request Headers) и сервером (Response Headers) отличаются, хотя есть и общие и для запросов и для ответов (General Headers)

Сервер узнал нашего пользователя по присланным cookie, и дальше предоставит ему доступ к личной информации. Так, ну вроде с сессиями и HTTP разобрались, теперь можно вернутся к PHP и его особенностям.

PHP и сессия

Я надеюсь, у вас уже установлен PHP на компьютере, т.к. дальше я буду приводить примеры, и их надо будет запускать

Язык PHP создавался под стать протоколу HTTP – т.е. основная его задача – это дать ответ на HTTP запрос и “умереть” освободив память и ресурсы. Следовательно, и механизм сессий работает в PHP не в автоматическом режиме, а в ручном, и нужно знать что вызвать, да в каком порядке.

Перво-наперво необходимо “стартовать” сессию – для этого воспользуемся функцией session_start() , создайте файл session.start.php со следующим содержимым:

Session_start();

И теперь – обновляем страничку, и видим, что браузер отправляет эту куку на сервер, можете попробовать пару раз обновить страницу, результат будет идентичным:

Итого, что мы имеем – теория совпала с практикой, и это просто отлично.

Следующий шаг – сохраним в сессию произвольное значение, для этого в PHP используется супер-глобальная переменная $_SESSION , сохранять будем текущее время – для этого вызовем функцию date() :

Session_start(); $_SESSION["time"] = date("H:i:s"); echo $_SESSION["time"];

Обновляем страничку и видим время сервера, обновляем ещё раз – и время обновилось. Давайте теперь сделаем так, чтобы установленное время не изменялось при каждом обновлении страницы:

Session_start(); if (!isset($_SESSION["time"])) { $_SESSION["time"] = date("H:i:s"); } echo $_SESSION["time"];

Обновляем – время не меняется, то что нужно. Но при этом мы помним, PHP умирает, значит данную сессию он где-то хранит, и мы найдём это место…

Всё тайное становится явным

По умолчанию, PHP хранит сессию в файлах – за это отвечает директива session.save_handler , путь по которому сохраняются файлы ищите в директиве session.save_path , либо воспользуйтесь функцией session_save_path() для получения необходимого пути.

В вашей конфигурации путь к файлам может быть не указан, тогда файлы сессии будут хранится во временных файлах вашей системы – вызовите функцию sys_get_temp_dir() и узнайте где это потаённое место.

Так, идём по данному пути и находим ваш файл сессии (у меня это файл sess_dap83arr6r3b56e0q7t5i0qf91), откроем его в текстовом редакторе:

Time|s:8:"16:19:51";

Как видим – вот оно наше время, вот в каком хитром формате хранится наша сессия, но мы можем внести правки, поменять время, или можем просто вписать любую строку, почему бы и нет:

Time|s:13:"\m/ (@.@) \m/";

Для преобразования этой строки в массив нужно воспользоваться функцией session_decode() , для обратного преобразования – session_encode() – это зовется сериализацией, вот только в PHP для сессий – она своя – особенная, хотя можно использовать и стандартную PHP сериализацию – пропишите в конфигурационной директиве session.serialize_handler значение php_serialize и будет вам счастье, и $_SESSION можно будет использовать без ограничений – в качестве индекса теперь вы сможете использовать цифры и специальные символы | и! в имени (за все 10+ лет работы, ни разу не надо было:)

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

$_SESSION["integer var"] = 123; $_SESSION["float var"] = 1.23; $_SESSION["octal var"] = 0x123; $_SESSION["string var"] = "Hello world"; $_SESSION["array var"] = ["one", "two", ]; $object = new stdClass(); $object->foo = "bar"; $object->arr = ["hello", "world"]; $_SESSION["object var"] = $object; $_SESSION["integer again"] = 42;

Так, что мы ещё не пробовали? Правильно – украсть “печеньки”, давайте запустим другой браузер и добавим в него теже самые cookie. Я вам для этого простенький javascript написал, скопируйте его в консоль браузера и запустите, только не забудьте идентификатор сессии поменять на свой:

Javascript:(function(){document.cookie="PHPSESSID=dap83arr6r3b56e0q7t5i0qf91;path=/;";window.location.reload();})()

Вот теперь у вас оба браузера смотрят на одну и туже сессию. Я выше упоминал, что расскажу о способах защиты, рассмотрим самый простой способ – привяжем сессию к браузеру, точнее к тому, как браузер представляется серверу – будем запоминать User-Agent и проверять его каждый раз:

Session_start(); if (!isset($_SESSION["time"])) { $_SESSION["ua"] = $_SERVER["HTTP_USER_AGENT"]; $_SESSION["time"] = date("H:i:s"); } if ($_SESSION["ua"] != $_SERVER["HTTP_USER_AGENT"]) { die("Wrong browser"); } echo $_SESSION["time"];

Это подделать сложнее, но всё ещё возможно, добавьте сюда ещё сохранение и проверку $_SERVER["REMOTE_ADDR"] и $_SERVER["HTTP_X_FORWARDED_FOR"] , и это уже более-менее будет похоже на защиту от злоумышленников посягающих на наши “печеньки”.

Ключевое слово в предыдущем абзаце похоже , в реальных проектах cookies уже давно «бегают» по HTTPS протоколу, таким образом никто их не сможет украсть без физического доступа к вашему компьютеру или смартфону

Задание
Добавьте в код проверку на IP пользователя, если проверка не прошла – удалите скомпрометированную сессию.

По шагам

А теперь поясню по шагам алгоритм, как работает сессия в PHP, на примере следующего кода (настройки по умолчанию):

Session_start(); $_SESSION["id"] = 42;

  1. после вызова session_start() PHP ищет в cookie идентификатор сессии по имени прописанном в session.name – это PHPSESSID
  2. если нет идентификатора – то он создаётся (см. session_id()), и создаёт пустой файл сессии по пути session.save_path с именем sess_{session_id()} , в ответ сервера будет добавлены заголовки, для установки cookie {session_name()}={session_id()}
  3. если идентификатор присутствует, то ищем файл сессии в папке session.save_path:
    • не находим – создаём пустой файл с именем sess_{$_COOKIE} (идентификатор может содержать лишь символы из диапазонов a-z , A-Z , 0-9 , запятую и знак минус)
    • находим, читаем файл и распаковываем данные (см. session_decode()) в супер-глобальную переменную $_SESSION
  4. когда скрипт закончил свою работу, то все данные из $_SESSION запаковывают с использованием session_encode() в файл по пути session.save_path с именем sess_{session_id()}

Задание
Задайте в вашем браузере произвольное значение куки с именем PHPSESSID , пусть это будет 1234567890 , обновите страницу, проверьте, что у вас создался новый файл sess_1234567890

А есть ли жизнь без “печенек”?

PHP может работать с сессией даже если cookie в браузере отключены, но тогда все URL на сайте будут содержать параметр с идентификатором вашей сессии, и да – это ещё настроить надо, но оно вам надо? Мне не приходилось это использовать, но если очень хочется – я просто скажу где копать:

А если надо сессию в базе данных хранить?

Для хранения сессии в БД потребуется изменить хранилище сессии и указать PHP как им пользоваться, для этой цели создан интерфейс SessionHandlerInterface и функция session_set_save_handler .

Отдельно замечу, что не надо писать собственные обработчики сессий для redis и memcache – когда вы устанавливаете данные расширения, то вместе с ними идут и соответствующие обработчики, так что RTFM наше всё. Ну и да, обработчик нужно указывать до вызова session_start() ;)

Задание
Реализуйте SessionHandlerInterface для хранения сессии в MySQL, проверьте, работает ли он.
Это задание со звёздочкой, для тех кто уже познакомился с базами данных.

Когда умирает сессия?

Интересный вопрос, можете задать его матёрым разработчикам – когда PHP удаляет файлы просроченных сессий? Ответ есть в официальном руководстве, но не в явном виде – так что запоминайте:

Сборщик мусора (garbage collection) может запускаться при вызове функции session_start() , вероятность запуска зависит от двух директив session.gc_probability и session.gc_divisor , первая выступает в качестве делимого, вторая – делителя, и по умолчанию эти значения 1 и 100, т.е. вероятность того, что сборщик будет запущен и файлы сессий будут удалены – примерно 1%.

Задание
Измените значение директивы session.gc_divisor так, чтобы сборщик мусора запускался каждый раз, проверьте что это так и происходит.

Самая тривиальная ошибка

Ошибка у которой более полумиллиона результатов в выдаче Google:

Cannot send session cookie – headers already sent by
Cannot send session cache limiter – headers already sent

Для получения таковой, создайте файл session.error.php со следующим содержимым:

Echo str_pad(" ", ini_get("output_buffering")); session_start();

Во второй строке странная “магия” – это фокус с буфером вывода, я ещё расскажу о нём в одной из следующих статей, пока считайте это лишь строкой длинной в 4096 символов, в данном случае – это всё пробелы

Запустите, предварительно удалив cookie, и получите приведенные ошибки, хоть текст ошибок и разный, но суть одна – поезд ушёл – сервер уже отправил браузеру содержимое страницы, и отправлять заголовки уже поздно, это не сработает, и в куках не появилось заветного идентификатора сессии. Если вы стокнулись с данной ошибкой – ищите место, где выводится текст
раньше времени, это может быть пробел до символов в одном из подключаемых файлов, и ладно если это пробел, может быть и какой-нить непечатный символ вроде BOM , так что будьте внимательны, и вас сия зараза не коснется (как-же, … гомерический смех).

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

Require_once "include/sess.php"; sess_start(); if (isset($_SESS["id"])) { echo $_SESS["id"]; } else { $_SESS["id"] = 42; }

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

В заключение

В этой статье вам дано шесть заданий, при этом они касаются не только работы с сессиями , но так же познакомят вас с MySQL и с функциями работы со строками . Для усвоения этого материала – отдельной статьи не нужно, хватит и мануала по приведенным ссылкам – никто за вас его читать не будет. Дерзайте!

P.S. Если узнали что-то новое из статьи – отблагодарите автора – зашарьте статью в социалках;)

  • Сергей Савенков

    какой то “куцый” обзор… как будто спешили куда то