Что такое код session_id


Содержание

Что такое session_id() и session_name()? Объясните, как они используются в следующем коде

Я понимаю, что приведенный выше код используется для завершения сеанса, но я не могу понять необходимость условия if и команды setcookie.

Также не могли бы вы объяснить, что именно является session_id() и session_name().

Понятное объяснение будет оценено по достоинству. Благодаря

PHP использует куки для управления сессиями; в частности, путем установки идентифицирующей пары ключ/значение для этого сеанса внутри файла cookie.

  • Имя сеанса — это имя файла cookie; имя по умолчанию для веб-сайтов на основе PHP — PHPSESSID . session_name() возвращает имя сеанса или, если передан параметр, обновляет имя сеанса.
  • Пара ключ/значение внутри cookie описывает идентификатор сеанса; ключ обозначает, что это идентификатор сеанса, а значение — сам идентификатор сеанса. session_id() возвращает идентификатор сеанса или, если передан параметр, обновляет идентификатор сеанса.

Код в вопросе проверяет, прошел ли сеанс с запросом: сначала запустив/повторно активировав сеанс с помощью session_start() , затем проверив наличие существующего файла cookie, соответствующего имени сеанса. Если код находит его, он заставляет браузер удалить cookie, установив дату истечения срока его действия в прошлом.

session_id() используется для получения или установки идентификатора сеанса для текущего сеанса.

session_name() возвращает имя текущего сеанса. Если указано имя, session_name() обновит имя сеанса и вернет имя старого сеанса.

id используется как первичный ключ (уникальный) для базы данных, в которой хранятся сеансы (по умолчанию только в файлах ondisk), name — это просто имя. Я не уверен, что name должен быть уникальным. Таким образом, в этом случае код проверяет, является ли session_id (получение данных из cookie браузера и поиск в локальном db) или если есть файл cookie с данным именем session_name. Если это так, он устанавливает время истечения срока действия файла cookie (клиентской стороны) до 43,2 минут назад и уничтожает сеанс (на стороне сервера).

isset ($ _SESSION [‘user_ >

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

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

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

Я не уверен, с чего начать устранение неполадок, потому что это все мне незнакомо. У меня есть таблица базы данных с полем ‘user_id’ (вместе с ‘username’ и ‘password’. В этом примере значение для user_id является цифрой 1.

Я попытался отобразить значение для user_id без успеха, даже когда вошел в систему …

Если я вставлю это в верхней части страницы …

…тогда это работает в обратном порядке. Если я вошел в систему, он отображает форму входа и отображает ссылку выхода из системы, когда я уже вышел из системы.

Вот (сильно отредактированный) код из login_submit.php …

Постскриптум Подсказка от обсуждения @ isset () не работал после входа в систему с $ _SESSION, установленным в значение val > Я вставил session_start (); вверху страницы, затем добавил этот скрипт:

Он говорит «еще не вошел», даже когда я вошел в систему.

Решение

Если я вставлю это вверху страницы … session_start (); …Затем это
работает …

Вы ответили на свой вопрос.

..задом наперед. Если я вошел в систему, он отображает форму входа и отображает ссылку выхода из системы, когда я уже вышел из системы.

Вы просто забыли отрицать утверждение if

вверху страницы, затем добавил этот скрипт:

Название сеанса user_id не valid таким образом никогда не совпадет.

Другие решения

Прежде чем использовать $ _SESSION, всегда сначала используйте session_start. В противном случае $ _SESSION не будет работать.

Если я вставлю это вверху страницы … session_start (); …Затем это
работает …

Вы ответили на свой вопрос.

..задом наперед. Если я вошел в систему, он отображает форму входа и отображает ссылку выхода из системы, когда я уже вышел из системы.

Вы просто забыли отрицать утверждение if

вверху страницы, затем добавил этот скрипт:

Название сеанса user_id не valid таким образом никогда не совпадет.

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

Сессии. Подробное описание работы и объяснение механизма.

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

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

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

Как устроены, и как работают сессии?
Для начала надо как-то идентифицировать браузер. Для этого надо выдать ему уникальный идентификатор и попросить передавать его с каждым запросом. Стыдно признаться, но когда я впервые узнал о сессиях, я думал, что это какой-то особый механизм, некий новый способ общения браузера с сервером — «сессии». Что идентификатор сессии передается каким-то особым образом. Разочарование было жестоким.
Сессии используют стандартные, хорошо известные способы передачи данных. Собственно, других-то просто и нет.
Идентификатор — это обычная переменная. По умолчанию ее имя — PHPSESSID.
Задача PHP отправить ее браузеру, чтобы тот вернул ее со следующим запросом. Из уже упоминавшегося раздела FAQ ясно, что переменную можно передать только двумя способами: в куках или POST/GET запросом.
PHP использует оба варианта.
За это отвечают две настройки в php.ini:
session.use_cookies — если равно 1, то PHP передает идентификатор в куках, если 0 — то нет.
session.use_trans_sid если равно 1, то PHP передает его, добавляя к URL и формам, если 0 — то нет.
Менять эти и другие параметры сессий можно так же, как и другие настройки PHP — в файле php.ini, а так же с помощью команды ini_set() или в файлах настройки веб-сервера

Если включена только первая, то при старте сессии (при каждом вызове session_start () ) клиенту устанавливается кука. Браузер исправно при каждом следующем запросе эту куку возвращает и PHP имеет идентификатор сессии. Проблемы начинаются, если браузер куки не возвращает. В этом случае, не получая куки с идентификатором, PHP будет все время стартовать новую сессию, и механизм работать не будет.

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

И браузер при клике на любую ссылку, или при нажатии на кнопку в форме, пошлет в запросе нужную нам переменную — идентификатор сессии!
По очевидным причинам идентификатор добавляется только к относительным ссылкам.

Теоретически, в наших с вами самодельных сессиях на куках и базе, можно самому, руками приписать ко всем ссылками передачу ид — и тогда наши собственные сессии будут работать независимо от кук. Но, согласитесь — приятнее, когда эту работу делает кто-то другой? ;-)

По умолчанию в последних версиях PHP включены обе опции. Как PHP поступает в этом случае? Кука выставляется всегда. А ссылки автодополняются только если РНР не обнаружил куку с идентификатором сессии. Когда пользователь в првый раз за этот сеанс заходит на сайт, ему ставится кука, и дополняются ссылки. При следующем запросе, если куки поддерживаются, PHP видит куку и перестает дополнять ссылки. Если куки не работают, то PHP продолжает исправно добавлять ид к ссылкам, и сессия не теряется.
Пользователи, у которых работают куки, увидят длинную ссылку с ид только один раз.

Фух. С передачей идентификатора закончили.
Теперь осталось привязать к нему файл с данными на стороне сервера.
PHP это сделает за нас. Достаточно просто написать
session_start ();
$_SESSION [ ‘test’ ]= ‘Hello world!’ ;
И PHP запишет в файл, связанный с этой сессией, переменную test.
Здесь очень важное замечание.
Массив $_SESSION — особенный.
В нем, собственно, и находятся переменные, которые мы ходим сделать доступными в различных скриптах.
Чтобы поместить переменную в сессию, достаточно присвоить ее элементу массива $_SESSION.
Чтобы получить ее значение — достаточно обратиться к тому же элементу. Пример будет чуть ниже.

Cборкой мусора — удалением устаревших файлов PHP тоже занимается сам. Как и кодированием данных и кучей всяких других нужных вещей. В результате этой заботы работа с сессиями оказывается очень простой.
Вот мы, собственно, и подошли к примеру работы сессий.
Пример очень маленький:
();
if (!isset( $_SESSION [ ‘counter’ ])) $_SESSION [ ‘counter’ ]= 0 ;
echo «Вы обновили эту страницу » . $_SESSION [ ‘counter’ ]++. » раз. » ;
echo «
. $_SERVER [ ‘PHP_SELF’ ]. «>обновить» ;
?>
Мы проверяем, есть ли у нас в сессии переменная counter, если нет, то создаем ее со значением 0, а дальше выводим ее значение и увеличиваем на единицу. Увеличенное значение запишется в сессию, и при следующем вызове скрипта переменная будет иметь значение 1, и так далее.
Все очень просто.

Илон Маск рекомендует:  Что такое код msql_fetch_object

Для того, чтобы иметь доступ к переменным сессии на любых страницах сайта, надо написать ТОЛЬКО ОДНУ(!) строчку в самом начале КАЖДОГО файла, в котором нам нужны сессии:
session_start ();
И далее обращаться к элементам массива $_SESSION. Например, проверка авторизации будет выглядеть примерно так:
session_start ();
if ( $_SESSION [ ‘authorized’ ]<> 1 ) <
header ( «Location: /auth.php» );
exit;
>

Удаление переменных из сессии.
Если у вас register_globals=off , то достаточно написать
unset( $_SESSION [ ‘var’ ]);
Если же нет, то тогда рядом с ней надо написать
session_unregister ( ‘var’ );

Область применения.
Очень важно понимать, для чего сессии стоит использовать, а для чего — нет.

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

Во-вторых. Важно четко себе представлять тот факт, что сессия — это сеанс работы с сайтом, так как его понимает человек. Пришел, поработал, закрыл браузер — сессия завершилась. Как сеанс в кино. Хочешь посмотреть еще один – покупай новый билет. Стартуй новый сеанс. Этому есть и техническое объяснение. Гарантированно механизм сессий работает только именно до закрытия браузера. Ведь у клиента могут не работать куки, а в этом случае, естественно, все дополненные идентификатором ссылки пропадут с его закрытием.
Правда, сессия может пропасть и без закрытия браузера. В силу ограничений, рассмотренных в самом главном разделе этого FAQ, механизм сессий не может определить тот момент, когда пользователь закрыл браузер. Для этого используется таймаут – заранее определенное время, по истечении которого мы считаем, что пользователь ушел с сайта. По умолчанию этот параметр равен 24 минутам.
Если вы хотите сохранять пользовательскую информацию на более длительный срок, то используйте куки и, если надо — базу данных на сервере. В частности, именно так работают все популярные системы авторизации:
— по факту идентификации пользователя стартует сессия и признак авторизованности передается в ней.
— Если надо «запомнить» пользователя, то ему ставится кука, его идентифицирующая.
— При следующем заходе пользователя на сайт, для того, чтобы авторизоваться, он должен либо ввести пароль, либо система сама его опознает по поставленной ранее куке, и стартует сессию. Новую сессию, а не продолжая старую.

В-третьих, не стоит стартовать сессии без разбору, каждому входящему на сайт. Это создаст совершенно лишнюю нагрузку. Не используйте сессии по пустякам – к примеру, в счетчиках. То, что спайлог называет сессиями, считается, конечно же, на основе статистики заходов, а не с помощью механизма сессий, аналогичного пхп-шному.
К тому же, возьмем поисковик, который индексирует ваш сайт. Если поисковый робот не поддерживает куки, то пхп по умолчанию будет поставлять к ссылкам PHPSESSID, что — согласистесь — может не сильно понравится поисковику, который, по слухам, и так-то динамические ссылки не жалует, а тут вообще при каждом заходе — новый адрес!
Если сессии используются для ограничения доступа к закрытому разделу сайта, то все просто поисковик и не должен его индексировать.
Если же приходится показывать одну и ту же страницу как авторизованным, так и не авторизованным пользователям, то тут поможет такой трюк – стартовать сессию только тем, кто ввел пароль, или тем, у кого уже стартовала сессия.
Для этого в начало каждой страницы вместо просто session_start () пишем
if (isset( $_REQUEST [ session_name ()])) session_start ();
таким образом, Мы стартуем сессию только тем, кто прислал идентификатор.
Соответственно, надо еще в первый раз отправить его пользователю – в момент авторизации.
Если имя и проль верные – пишем session_start () !

Самыми распространенными ошибками, которые выдает РНР при попытке работать с сессиями, являются такие:
Две из них,
Warning: Cannot send session cookie — headers already sent
Warning: Cannot send session cache limiter — headers already sent
вызваны одной и той же причиной, решение описано в этом факе здесь
Третья,
Warning: open(/tmp\sess_SID, O_RDWR) failed: No such file or directory (2) in full_script_path on line number (ранее она выглядела, как Warning: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/tmp) ),
если перевести ее с английского, подробно объясняет проблему: недоступен указанный в php.ini путь к каталогу, в который пишутся файлы сессий. Эту ошибку исправить проще всего. Просто прописать каталог, который существует, и доступен на запись, например,
session.save_path = c:\windows\temp
И не забыть перезагрузить апач после этого.

Как выясняется, сообразительность людская не имеет пределов, и поэтому я вынужден пояснить:
сообщение о третьей ошибке (невозможно найти каталог) НЕИЗБЕЖНО приведет к появлению первых двух, поскольку сообщение об ошибке — это вывод в браузер и после него заголовками пользоваться нельзя. Поэтому не спешите искать преждевременный вывод, а сначала пропишите правильный путь!

Следующей по распространенности проблемой при работе с сессиями является тяжелое наследие register_globals. НЕ давайте переменным скрипта имена, совпадающие с индексами массива $_SESSION!
При register_globals=on значения будут перезаписывать друг друга, и вы запутаетесь.
А при register_globals=off появится другая ошибка: «Your script possibly relies on a session side-effect which existed until PHP 4.2.3.», в случае, если в скрипте есть переменная сессии не имеющая значения, и глобальная переменная с тем же именем. Чтобы от неё избавиться, надо всегда инициализировать переменные перед использованием (или хотя бы проверять на существование) и не давать глобальным переменным имена, совпадающие с индексами массива $_SESSION.

Если не работает, но и никаких сообщений не выводится, то добавьте в самое начало скрипта две строчки, отвечающие за вывод ВСЕХ ошибок на экран — вполне возможно, что ошибки есть, но вы их просто не видите.
ini_set ( ‘display_errors’ , 1 );
error_reporting ( E_ALL );
или смотрите ошибки в error_log. Вообще, тема отображения сообщений об ошибках выходит за рамки данной статьи, поэтому просто убедитесь хотя бы, что вы можете их видеть. Чуть продробнее о поиске ошибок можно прочитать в этом разделе.

Если вы уверены, что ошибок нет, но приведенный пример не работает все равно, то, возможно, в PHP не включена передача ид через урл, а куки по каким-то причинам не работают.
Смотрите, что у вас с куками.
Вообще, если у вас «не работают» сессии, то сначала попробуйте передать идентификатор сессии руками, то есть, сделать ссылку и приписать к ней идентификатор:
();
if (!isset( $_SESSION [ ‘counter’ ])) $_SESSION [ ‘counter’ ]= 0 ;
echo «Вы обновили эту страницу » . $_SESSION [ ‘counter’ ]++. » раз.

. $_SERVER [ ‘PHP_SELF’ ]. ‘?’ . session_name (). ‘=’ . session_id (). «>обновить» ;
?>
При этом следует убедиться, что не включена директива session.use_only_cookies , которая запрещает PHP принимать идентификатор сессии, если он был передан через URL

Если этот пример не заработает, то проблема либо в банальных опечатках (половина «проблем» с сессиями происходит от неправильно написанного имени переменной), либо в слишком старой версии PHP: поддержка сессий появилась в версии 4.0, а массив $_SESSION — в 4.1 (До этого использовался $HTTP_SESSION_VARS ).
Если же заработает — то проблема в куках. Отслеживайте — что за куку ставит сервер браузеру, возвращает ли браузер ее. Искать очень полезно, просматривая просматривая обмен HTTP-заголовками между браузером и сервером.
Объяснение принципа работы кук выходит за рамки этого и так уж слишком большого текста, но хотя бы убедитесь, что сервер куку с идентификатором посылает, а браузер — возвращает. И при этом идентификаторы совпадают друг с другом =)
Установка куки должна выглядеть, как
Set-Cookie: PHPSESS >
или как
Set-Cookie: PHPSESS >
(если вы запрашиваете скрипт не из корневого каталога)
Ответ сервера должен выглядеть, как
Cookie: PHPSESS >
либо
Cookie: PHPSESS >
если браузер возвращает другие куки, кроме идентификатора сессии.

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

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

Еще одна проблема может возникнуть, если вы используете перенаправление через header или навигацию с помощью JavaScript.
Дело в том, что РНР автоматически дописывает идентификатор сессии только к ссылкам вида , но не делает этого для header-ов, яваскрипта, мета-тегов.
Поэтому надо добавлять идентификатор руками, например, так:
header ( «Location: /script.php?» . session_name (). ‘=’ . session_id ());

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

Так же, весьма редкая, и совершенно непонятно, откуда появляющаяся, проблема бывает в том, что настройка session.save_handler имеет значение, отличное от files. Если это не так — исправляйте.

Безопасность
Безопасность сессий — тема обширная. Поэтому остановлюсь на нескольких основных моментах.
Самый хрестоматийный — не передавать идентификатор через адресную строку. Об этом написано даже в php.ini, но это ограничивает функциональность сессий. Если вы решите последовать этому совету, то кроме session.use_trans_s > Желательно привязывать сессию к IP адресу: таким образом, если идентификатор будет украден, то злодей все равно не сможет им воспользоваться в большинстве случаев.
Рекомендуется пользоваться директивой session.save_path, с помощью которой задать собственный каталог для сохранения файлов сессий. Это более безопасно, чем когда они хранятся в общем временном каталоге сервера по умолчанию.

Дополнительная информация:

  • Кроме кук, механизм сессий посылает еще и заголовки, запрещающие кэширование страниц (тот самый cache limiter). Для html это правильно и необходимо. Но вот когда вы пытаетесь скриптом, проверяющим авторизацию, отдать файл, то интернет эксплорер отказывается его скачивать. Именно из-за этого заголовка. Вызов
    session_cache_limiter ( «private» );
    перед стартом сессии должен решить проблему.
  • Как это ни кажется странным, но в массиве $_SESSION нельзя использовать числовые индексы — $_SESSION [ 1 ], $_SESSION [ ’10’ ] — cессии работать не будут.
  • Где-то между версиями 4.2 и 5.0 невозможно было установить session.use_trans_sid с помощью ini_set () . Начиная с 5.0 уже можно снова.
  • До версии 4.3.3 куку PHP отправлял куку только если при старте сессии в запросе отсутстввал идентификатор. Теперь же кука посылается при каждом вызове session_start ()
  • Пример авторизации с помощью сессий
    Проиллюстрируем все вышенаписанное небольшим примером:
    создадим файл auth.php:
    if (isset( $_POST [ ‘auth_name’ ]))
    <
    $sql = «SELECT * FROM users WHERE name=?s» ;
    $row = $db -> getRow ( $sql , $_POST [ ‘auth_name’ ]);
    if ( $row && password_verify ( $_POST [ ‘auth_pass’ ], $row [ ‘pass’ ])) <
    $_SESSION [ ‘user_id’ ] = $row [ ‘id’ ];
    >
    header ( «Location: http://» . $_SERVER [ ‘HTTP_HOST’ ]. $_SERVER [ ‘REQUEST_URI’ ]);
    exit;
    >

    if (isset( $_GET [ ‘action’ ]) AND $_GET [ ‘action’ ]== «logout» ) <
    session_start ();
    session_destroy ();
    header ( «Location: http://» . $_SERVER [ ‘HTTP_HOST’ ]. «/» );
    exit;
    >

    if (!isset( $_SESSION [ ‘user_id’ ])) <
    ?>

    exit;
    >

    Функция Session_ >Функция Session_id получает или устанавливает ID текущей сессии.
    Если ID специфицирован, он замещает текущий Session id. При этом Session_id необходимо вызывать до Session_start. Параметр ID должен содержать только буквенно-цифровые символы.

    Константа SID также может использоваться для запрашивания текущих имени и ID сессии как строки, пригодной для добавления в URL. Будьте внимательны, поскольку SID определена только в том случае, если клиент не отправил данные в сессионный Cookie.

    Илон Маск рекомендует:  Что такое код session_destroy

    HTTP сессия. Session. Состояние сеанса. Работа с сессиями в ASP.NET MVC

    Давайте рассмотрим такое понятие как сессия (HTTP-сессия, Session). Или по-другому, сеанс пользователя. Почему важно понимать механизм работы сессий. И посмотрим, как можно работать с состояниями сеансов на платформе ASP.NET.

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

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

    Что, если оставить stateless-природу протокола HTTP и не идентифицировать пользователя? Без состояний сеанса можно легко обойтись, если на вашем сайте представлена статичная (обезличенная) информация, например, новостная статья, состоящая из текста и изображений. В таком контексте совершенно необязательно ассоциировать несколько запросов с одним пользователем. Ведь содержание статьи никак не изменится, будь то десять запросов с одного устройства, либо десять запросов от разных людей с разных устройств.

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

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

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

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

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

    1. скрытые поля на HTML-форме (hidden form fields)
    2. куки (cookies)
    3. сессия (session, session State)

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

    Скрытые поля на HTML-форме (hidden form fields)

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

    В данном примере мы на первой html-форме получаем имя пользователя. Далее в контроллере в методе Forms2() мы извлекаем это значение из коллекции Form и передаем в представление посредством объекта ViewBag. В этом представлении генерируется код новой формы и в скрытом поле сохраняется имя пользователя. Таким образом, значение имени пользователя будет передано уже на третью формы вместе с дополнительной информацией — значением поля с именем «foodName». И так далее.

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

    • Во-первых, этот вариант не будет работать, если html-формы на наших страницах статичны, то есть жестко закодированы. И чтобы это исправить, чтобы повлиять на html-разметку мы прибегаем к помощи какой-нибудь серверной технологии (в данном случае механизм ViewBag);
    • Это безопасность. Хоть вводимые нами данные не передаются через url-параметры в адресной строке и визуально не видны на странице, мы с легкостью можем их получить или подменить или удалить или украсть просто изучив исходный код страницы или структуру запроса;

    Куки (cookies)

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

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

    Серверный механизм управления сессией (Session, SessionState)

    Разберем, как работает механизм сессии со стороны сервера и со стороны клиента.

    При стандартных настройках работы состояния сеанса для отслеживания серии запросов от одного клиента используется т.н. сессионная куки (session cookie). Алгоритм следующий:

    1. Абсолютно для каждого нового запроса на сервер (неважно, разные это клиенты или один) ASP.NET генерирует уникальный идентификатор сессии.
      Идентификатор сессии представляет собой случайно сгенерированное число, закодированное с помощью специального алгоритма в строку длиной 24 символа. Строка состоит из литералов от A до Z в нижнем регистре, а также чисел от 0 до 5. Пример идентификатора — hjnyuijl1pam3vox2h5i41in
    2. Если в течение текущего запроса данные клиента НЕ сохраняются для дальнейшей работы с ним, то и время жизни сессии этого клиента заканчивается (фактически не начавшись). При этом ранее сгенерированный идентификатор сессии становится недействительным (так как не был использован). В ответ на такой запрос клиент не получает ничего, чтобы связало его с новой сессией.
    3. Если же данные клиента (например, имя, адрес доставки товара) сохраняются на сервере, ASP.NET связывает сохраненные данные с ранее сгенерированным идентификатором сессии. Далее создается специальная сессионная куки, и в нее записывается также этот идентификатор. Эта куки добавляется в ответ на запрос и сохраняется в браузере клиента. Таким образом, создается связь клиента и его персонализированной информации на сервере. Новая сессия для данного клиента создана.
    4. При каждом следующем запросе клиент передает на сервер персональный идентификатор сессии через куки. Сервер сопоставляет идентификаторы и «узнает» клиента в рамках текущей сессии.
    5. До тех пор пока клиент передает свой персональный ключ, сессия считается активной. Сессия может закончиться по разным причинам, например, вручную на стороне сервера или по истечении какого-то установленного времени (таймаут).

    От теории перейдем к практике. Давайте запрограммируем данный алгоритм и посмотрим, как он выполняется. Для этого используем специальный класс HttpSessionState . При работе в контроллере можно воспользоваться свойством HttpContext.Session . Работать с сессией очень просто, как с любой NameValueCollection :

    В этом участке кода мы записываем в состояние сеанса имя пользователя. Это имя мы забираем с html-формы, которую он нам отправил. Дополнительно через свойства мы узнаем, создана ли эта сессия только что, то есть в рамках текущего запроса (если да, то и значение свойства IsNewSession будет равняться true), и уникальный идентификатор сессии. Этот идентификатор после обработки запроса будет автоматически записан в сессионную куки (если еще нет) и отправлен в ответе клиенту.

    В браузере клиента можно наблюдать соответствующую куки и идентификатор его сессии:

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

    Как видно, работать с сессиями очень просто и удобно. Большинство процессов, связанных с обработкой сессии, происходит автоматически в фоновом режиме. Естественно, разработчик может вмешаться на любой стадии обработки сессии и внести свои коррективы.

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

    Item[index] – возвращает элемент данных по его индексу
    Item[key] – возвращает элемент данных по его ключу
    Remove(index) – удаляет элемент данных по его индексу
    Remove(key) – удаляет элемент данных по его ключу
    Clear() – удаляет все данные
    Count – возвращает общее количество элементов данных для текущей сессии
    Abandon() – принудительно завершить сессию
    SessionID — возвращает идентификатор текущей сессии
    IsNewSession – возвращает true если сессия была создана в рамках текущего запроса
    Timeout – возвращает число минут, допустимое между запросами, перед тем как сессия завершится по причине таймаута (по умолчанию, 20 минут)

    Изменить настройки для сессии можно либо программно в коде посредством членов класса HttpSessionState , либо через конфигурацию приложения (файл web.config). Например:

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

    Как использовать сессии и переменные сессий в PHP

    Russian (Pусский) translation by Ellen Nelson (you can also view the original English article)

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

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

    Что такое сессия в PHP?

    Сессия — это механизм для сохранения информации на разных веб-страницах для идентификации пользователей пока они бродят по сайту или приложению. Вам интересно, почему сеансы нужны для веб-сайта? Чтобы понять, почему сеансы необходимы, нам нужно чуть вернуться назад и посмотреть, как работает HTTP-протокол.

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

    Следующая диаграмма вкратце изображает протокол HTTP.

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

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

    Обработка входа с сессиями и файлами «куки» (cookie)

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

    1. Пользователь открывает страницу входа на веб-сайт.
    2. После отправки формы входа, сервер, на другом конце, аутентифицирует запрос, проверив введённые учётные данные.
    3. Если учётные данные, введённые пользователем, верны, сервер создаёт новый сеанс. Сервер генерирует уникальное случайное число, которое называется идентификатором сеанса. Также, на сервере, создаётся новый файл, который используется для хранения информации, относящейся к сеансу.
    4. Затем, идентификатор сеанса передаётся обратно пользователю, вместе с тем, что он запросил. За кулисами этот идентификатор сеанса отправляется в заголовке ответа «куки» PHPSESSID (так называется по умолчанию).
    5. Когда браузер получает ответ от сервера, он получает заголовок куки-файла PHPSESSID . Если в браузере разрешены «куки», то он сохранит этот PHPSESSID , в котором хранится идентификатор сеанса, переданный сервером.
    6. Для последующих запросов, «кука» PHPSESSID передаётся обратно на сервер. Когда сервер получает «куку» PHPSESSID , он пытается инициализировать сеанс с этим идентификатором сеанса. Он делает это, загружая файл сеанса, который был создан ранее во время инициализации сеанса. Затем он инициализирует суперглобальную переменную массива $_SESSION с данными, хранящимися в файле сеанса.

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

    На следующей диаграмме показано, как протокол HTTP работает с сеансами.

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

    Как запустить сессию

    В этом разделе мы обсудим, как запустить сессию в PHP.

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

    Использование функции session_start

    Метод, в котором сессия запускается функцией session_start , вы будете видеть часто.

    Важно, чтобы функция session_start вызывалась в начале скрипта, перед отправкой чего-либо браузеру. В противном случае, вы столкнётесь с печально известной ошибкой Headers are already sent .

    Автоматический запуск сеанса

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

    В файле php.ini есть параметр session.auto_start , который позволяет запускать сеанс автоматически для каждого запроса. По умолчанию установлено значение 0 (выкл), и вы можете установить его на 1 (вкл), чтобы включить функцию автоматического запуска.

    С другой стороны, если у вас нет доступа к файлу php.ini, и вы используете веб-сервер Apache, эту переменную можно задать с помощью файла .htaccess.

    Если вы добавите строку выше в ваш .htaccess файл, то это должно автоматически запускать сессии в вашем PHP-приложении.

    Как получить идентификатор сеанса

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

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

    Важно отметить, что если вы хотите начать сеанс с помощью своего идентификатора сеанса, функция session_id должна стоять перед вызовом session_start .

    Создание переменных сеанса

    В этом разделе мы изучим, как инициализировать переменные сессии в PHP.

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

    Давайте рассмотрим следующий пример кода, который показывает, как инициализировать переменные сеанса.

    Как видите, мы запустили сессию в начале скрипта, используя функцию session_start . После этого мы инициализировали несколько переменных сессии. Наконец, мы использовали эти переменные через суперглобальную переменную $_SESSION .

    При хранении данных сеанса с помощью $_SESSION , в итоге, они хранятся в соответствующем файле сессии на сервере, который был создан, когда сессия была запущена. Таким образом данные сеанса совместно используются несколькими запросами.

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

    Как изменять и удалять переменные сеанса

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

    Давайте посмотрим, как изменять переменные сессии.

    В приведённом выше коде, мы проверяем, установлена ли переменная $_SESSION[‘count’] . Если не установлена, мы устанавливаем её равной 1 , в противном случае, увеличим её на 1 . Таким образом, если вы обновите эту страницу несколько раз, вы должны увидеть, что счётчик, каждый раз, увеличивается на единицу!

    С другой стороны, если вы хотите удалить переменную сеанса, вы можете использовать функцию unset , как показано в следующем фрагменте.

    Таким образом, вы больше не сможете обращаться к переменной $_SESSION [‘logged_in_user_id’] , поскольку она удалена функцией unset . Вот так вы можете изменить информацию о сеансе.

    Как уничтожить сессию

    В этом разделе мы увидим, как можно уничтожить сессию. В предыдущем разделе мы рассмотрели функцию unset , которая используется для удаления определённых переменных сеанса. С другой стороны, если вы хотите удалить сразу все данные, связанные с сеансом, вы можете использовать функцию session_destroy .

    Попробуем понять, как это работает в следующем примере.

    Функция session_destroy удаляет всё, что хранится в текущем сеансе. Таким образом, с последующими запросами вы увидите пустую переменную $_SESSION , поскольку данные сеанса, хранящиеся на диске, были удалены функцией session_destroy .

    Как правило, функцию session_destroy нужно использовать, когда пользователь выходит из системы.

    Заключение

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

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

    Что такое код session_id

    В случае, когда пользователь после этого закроет страницу/выйдет с сайта и 30 минут не будет больше совершать никаких взаимодействий с сайтом — отправлять хиты в Google Analytics, то сеанс этого пользователя будет засчитан как отказ.
    Если же, пользователь совершит два или более взаимодействий (отправит несколько хитов на протяжении 30 минут), то GA посчитает это как полноценный сеанс/сессию.

    Сессия автоматически заканчивается в полночь (23:59:59 вечера).
    Например если пользователь просматривает сайт с 11:45 вечера, его сессия автоматически завершается в 11:59:59, даже если он продолжает взаимодействовать с сайтом. В 12 часов ночи GA создаёт новую сессию, таким образом у данного пользователя получаются две сессии, вместо одной.

    Google Analytics создаёт новую сессию, если пользователь вернется на сайт через другой источник кампании. Неважно, возвращается ли пользователь в течение 30 минут или по истечении 30 минут, каждый раз, когда источник кампании меняется, GA автоматически создаёт новую сессию.

    Источниками кампании могут быть: поисковые системы, веб-сайты, URL-адреса с параметрами кампании.

    Например , если пользователь первый раз пришел на сайт через органический поиск, но позже (допустим через 15 минут) пришел на сайт кликнув по рекламному объявлению. То в этом случае GA cоздаст новую сессию, независимо от того, что время предыдущего сеанса ещё не закончилось, так как пользователь поменял источник с которого он попал на сайт в первый раз.

    Второй пример
    . Пользователь попал на сайт кликнув по рекламному объявлению(через контекст), но допустим, что через 15 минут, он заново кликнул на то же рекламное объявление и попал на сайт.
    Тут есть два условия: Если это объявление было создано используя автопометку AdWords, GA создаст новую сессию, так как при автопометке автоматически меняются параметры источника кампании, потому что при каждом клике на одно и тоже рекламное объявление меняется значение параметра GCLID.
    Если же это объявление было помечено вручную, без использования автопометки AdWords, GA не будет создавать новую сессию, так как параметры источника кампании не меняются.


    Третий пример
    . Пользователь попал на сайт через органический поиск, но допустим, что через 15 минут он вернулся на сайт, набрав адрес сайта в строке браузера(прямой заход), Ga не будет создавать новую сессию, так как прямой заход не меняет источник кампании.

    Не пойму, в чем проблема при авторизация с сессией на php?

    Доброго времени суток. Имею вот такую систему авторизации на сайте:

    Он нормально проверяет правильность пароль и выводит соответствующую надпись.
    Но если пароль правильный, то он должен вместе формы авторизации выдать какой то контент, но вместо этого форма авторизации остается, и выходит ошибка «Warning: session_start() [function.session-start]: Cannot send session cookie» . Нагуглил лишь то, что session_start(); должен быть в начале кода, но и это не помогает. Помогите пожалуйста разобраться. И еще, впервые пишу сайт то на php с mysql.

    • Вопрос задан более трёх лет назад
    • 2424 просмотра

    Нагуглил лишь то, что session_start(); должен быть в начале кода, но и это не помогает.

    Вспомнил. Скорее всего, это BOM гадит.
    Надо сохранять файл в кодировке UTF-8 without BOM, а лучше вообще сменить редактор на что-нибудь пристойное, с подсветкой кода хотя бы.

    @FanatPHP Если не трудно, можешь глянуть что в этом коде не так? Он должен редактировать запись. Сейчас он в форму редактирования данные заносит, но при отправке данные не переписываются в БД. Скажите что говнокод, но я пока только учусь, это первое что я делаю на php.
    >else
    <
    $ ];
    >
    $result = mysql_query(«SELECT title, zayavka, «) or die(mysql_error());
    $news = mysql_fetch_array($result);
    echo
    $title=mysql_result($result,0,»title»);
    $zayavka=mysql_result($result,0,»zayavka»);
    /* Создание формы для редактирования */
    print «»;
    print «

    if(isset($_POST[edit])) <
    $title=$_POST[‘title’];
    $zayavka=$_POST[‘zayavka’];
    $login=$_SESSION[‘name’];
    $status=’Открыт’;
    <
    $query=mysql_query(«INSERT INTO zayavki VALUES (»,’$login’,’$title’,’$zayavka’,’$status’,NOW())») or die(mysql_error());
    >

    @Bert
    else
    $ ];
    //if table row `id` INT то $id без ковычек »
    $query=»SELECT `title`,`zayavka`,` > $result=mysql_query($query);
    if(mysql_num_rows($result)) // условие если были затронуты строки то:
    <
    $array=array(); // создаем массив, куда записывается MYSQL выборка
    while($row=mysql_fetch_assoc($result)) // пока $row присваивает результат по названию столбцов таблицы
    $array[]=$row; // заполняем массив
    >

    /* Создание формы для редактирования */

    if(isset($_POST[‘edit’]))
    <
    $title=$_POST[‘title’];
    $zayavka=$_POST[‘zayavka’];
    $login=$_SESSION[‘name’];
    $status=’Открыт’;

    $query=»UPDATE `zayavki` SET `login`=’$login’,`title`=’$title’,`zayavka`=’$zayavka’,`status`=’$status’,`date`=NOW() WHERE ` > $result=mysql_query($query);
    if(mysql_affected_rows()>0)
    echo «Заявка успешно добавлена»;
    else
    echo «Произошла ошибка добавления заявки»;
    >
    ?>

    Что такое код session_id

    В случае, когда пользователь после этого закроет страницу/выйдет с сайта и 30 минут не будет больше совершать никаких взаимодействий с сайтом — отправлять хиты в Google Analytics, то сеанс этого пользователя будет засчитан как отказ.
    Если же, пользователь совершит два или более взаимодействий (отправит несколько хитов на протяжении 30 минут), то GA посчитает это как полноценный сеанс/сессию.

    Сессия автоматически заканчивается в полночь (23:59:59 вечера).
    Например если пользователь просматривает сайт с 11:45 вечера, его сессия автоматически завершается в 11:59:59, даже если он продолжает взаимодействовать с сайтом. В 12 часов ночи GA создаёт новую сессию, таким образом у данного пользователя получаются две сессии, вместо одной.

    Google Analytics создаёт новую сессию, если пользователь вернется на сайт через другой источник кампании. Неважно, возвращается ли пользователь в течение 30 минут или по истечении 30 минут, каждый раз, когда источник кампании меняется, GA автоматически создаёт новую сессию.

    Источниками кампании могут быть: поисковые системы, веб-сайты, URL-адреса с параметрами кампании.

    Например , если пользователь первый раз пришел на сайт через органический поиск, но позже (допустим через 15 минут) пришел на сайт кликнув по рекламному объявлению. То в этом случае GA cоздаст новую сессию, независимо от того, что время предыдущего сеанса ещё не закончилось, так как пользователь поменял источник с которого он попал на сайт в первый раз.

    Второй пример
    . Пользователь попал на сайт кликнув по рекламному объявлению(через контекст), но допустим, что через 15 минут, он заново кликнул на то же рекламное объявление и попал на сайт.
    Тут есть два условия: Если это объявление было создано используя автопометку AdWords, GA создаст новую сессию, так как при автопометке автоматически меняются параметры источника кампании, потому что при каждом клике на одно и тоже рекламное объявление меняется значение параметра GCLID.
    Если же это объявление было помечено вручную, без использования автопометки AdWords, GA не будет создавать новую сессию, так как параметры источника кампании не меняются.


    Третий пример
    . Пользователь попал на сайт через органический поиск, но допустим, что через 15 минут он вернулся на сайт, набрав адрес сайта в строке браузера(прямой заход), Ga не будет создавать новую сессию, так как прямой заход не меняет источник кампании.

    Функция Session_ >Функция Session_id получает или устанавливает ID текущей сессии.
    Если ID специфицирован, он замещает текущий Session id. При этом Session_id необходимо вызывать до Session_start. Параметр ID должен содержать только буквенно-цифровые символы.

    Константа SID также может использоваться для запрашивания текущих имени и ID сессии как строки, пригодной для добавления в URL. Будьте внимательны, поскольку SID определена только в том случае, если клиент не отправил данные в сессионный Cookie.

    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL