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

По умолчанию это выглядит вот так:

  • Клиенту устанавливается кука PHPSESSID, значение которой - идентификатор сессии клиента. Обычно это строка примерно такого вида - "cmcjeagp3289oga05a2nw3qga6"

  • На сервере к этому идентификатору привязывается место, в котором хранятся данные именно этого клиента.

Имя куки, которую устанавливает php можно изменить в параметре session.name в php.ini:

session.name = 'ваше-имя-сессионной-куки'

или с помощью ini_set:

ini_set('session.name', 'ваше-имя-сессионной-куки');

или с помощью вызова session_name:

session_name('ваше-имя-сессионной-куки');

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

В PHP-сессии по умолчанию выключены и для их включения необходимо вызывать session_start(), либо настроить в php.ini автозапуск сессий:

session.auto_start = 1

Если session.auto_start выключен, то массив $_SESSION не будет связан с конкретной сессий до вызова session_start(). Поэтому не забывайте запускать session_start() в самом начале работы, до выполнения какой-либо логики.

Каким же образом сессии хранятся на сервере?

За это отвечает настройка session.save_handler и ее уточняющая настройка session.save_path. Если установить на сервер расширение php-memcached будут доступны следующие варианты для session.save_handler:

  • "files" - хранить сессии в файлах. В session.save_path заполняется путь к директории, в которой будут хранится сессии

  • "memcached" - хранить сессии на сервере memcached. В session.save_path указывается строка подключения к серверу, например: "127.0.0.1:11211". Подробнее это описано здесь

Собственно, в случае memcached ключ образуется из идентификатора сессии, а в случае работы с файлами, имя файла составляется из идентификатора.

Рабочий пример

Как пользоваться сессиями на простом и рабочем примере:

session_name('my-session-name'); //задаем имя куке до вызова session_start
session_start();                                     //запускаем сессию (указываем session_start явно, чтобы не зависеть от настроек конкретного сервера
var_dump($_SESSION);                      //выводим, что имеется в сессии

//создаем счетчик при первом обращении
if (empty($_SESSION['count'])) {
    $_SESSION['count'] = 0;  
}

//считаем кол-во запросов пользователя
$_SESSION['count']++;

Если обращаться к этому файлу в браузере, будут вот такие ответы:

array(1) { }

Следующий ответ после F5:

array(1) { ["count"]=> int(1) }

Следующий ответ после F5:

array(1) { ["count"]=> int(2) }

Можно посмотреть на имена кук и поиграть с этим руками:

$ curl -i http://127.0.0.1/
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Fri, 10 Feb 2017 21:12:19 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: my-session-name=ft766dgk625rno96c638uqb643; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache

array(0) {

}


Мы видим, что нам дали ответ с заголовком Set-Cookie и установили идентификатор сессии. Первый ответ - пустой массив, как и в случае с браузером. Попробуем отправить второй запрос, передав куку:

$ curl -i --cookie my-session-name=ft766dgk625rno96c638uqb643 http://127.0.0.1/
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Fri, 10 Feb 2017 21:13:22 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache

array(1) {
 ["count"]=>
 int(1)
}

И еще раз:

$ curl -i --cookie my-session-name=ft766dgk625rno96c638uqb643 http://127.0.0.1/
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Fri, 10 Feb 2017 21:13:32 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache

array(1) 
  ["count"]=>
  int(2)
}

Если мы изменим куку, у нас будет другая (в нашем случае новая пустая) сессия:

$ curl -i --cookie my-session-name=blabla http://127.0.0.1/
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Fri, 10 Feb 2017 21:13:55 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache

array(0) { }

При повторном обращении "левая" сессия будет работать:

$ curl -i --cookie my-session-name=blabla http://127.0.0.1/
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Fri, 10 Feb 2017 21:14:15 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache

array(1) {
  ["count"]=>
  int(1)
}

Полезная документация