Powrót do kategorii
Backend
tagi
memcache, sesje, sessions, zend framework, zf2,

Sesje w Zend Framework 2

Grzegorz
Grzegorz, 09/02/2015

Dlaczego stosować sesje

Zbudowanie profesjonalnej aplikacji bez wykorzystania sesji jest praktycznie niemożliwe. Jako że protokół HTTP jest bezstanowy, serwer WWW musi mieć możliwość zidentyfikowania powracającego użytkownika aby zaserwować mu odpowiednie dane. Sesje służą więc do identyfikacji użytkowników i składowania danych. Działanie ich jest bardzo proste. Serwer tworzy unikalny identyfikator za pomocą którego jest identyfikowany na serwerze plik (zbiór) danych dotyczący danego użytkownika. Ten sam identyfikator jest zostawiany u klienta (np. za pomocą cookies) i w momencie przyjścia żądania na serwer sprawdzany jest ten identyfikator i porównywany z zasobami serwera. Dzięki temu serwer wie, który użytkownik wysłał żądanie.

Standardowe korzystanie z sesji w ZF2

Główną klasa odpowiedzialną za obsługę/zarządzanie sesji w ZF2 jest Zend\Session\SessionManager.
Zajmuje się ona inicjalizacją sesji, jej konfiguracją, zapisem danych do sesji oraz jej zniszczeniem.

Na początku należy dokonać konfiguracji sesji w pliku konfiguracyjnym a następnie należy zainicjować sesję. Można to zrobić w pliku Module.php

Standardowa obsługa wygląda następująco:

public function bootstrapSession($e)
{
    $session = $e->getApplication()
        ->getServiceManager()
        ->get('Zend\Session\SessionManager');
    $session->start();

    $container = new Container('initialized');
    if (!isset($container->init)) {
        $serviceManager = $e->getApplication()->getServiceManager();
        $request = $serviceManager->get('Request');

        $session->regenerateId(true);
        $container->init = 1;
        $container->remoteAddr = $request->getServer()->get('REMOTE_ADDR');
        $container->httpUserAgent = $request->getServer()->get('HTTP_USER_AGENT');

        $config = $serviceManager->get('Config');
        if (!isset($config['session'])) {
            return;
        }

        $sessionConfig = $config['session'];
        if (isset($sessionConfig['validators'])) {
            $chain = $session->getValidatorChain();

            foreach ($sessionConfig['validators'] as $validator) {
                switch ($validator) {
                    case 'Zend\Session\Validator\HttpUserAgent':
                        $validator = new $validator($container->httpUserAgent);
                        break;
                    case 'Zend\Session\Validator\RemoteAddr':
                        $validator = new $validator($container->remoteAddr);
                        break;
                    default:
                        $validator = new $validator();
                }

                $chain->attach('session.validate', array($validator, 'isValid'));
            }
        }
    }
}


public function getServiceConfig()
{
    return array(
        'factories' => array(
            'Zend\Session\SessionManager' => function ($sm) {
                $config = $sm->get('config');
                if (isset($config['session'])) {
                    $session = $config['session'];

                    $sessionConfig = null;
                    if (isset($session['config'])) {
                        $class = isset($session['config']['class']) ? $session['config']['class'] : 'Zend\Session\Config\SessionConfig';
                        $options = isset($session['config']['options']) ? $session['config']['options'] : array();
                        $sessionConfig = new $class();
                        $sessionConfig->setOptions($options);
                    }

                    $sessionStorage = null;
                    if (isset($session['storage'])) {
                        $class = $session['storage'];
                        $sessionStorage = new $class();
                    }

                    $sessionSaveHandler = null;

                    $sessionManager = new SessionManager($sessionConfig, $sessionStorage, $sessionSaveHandler);
                } else {
                    $sessionManager = new SessionManager();
                }
                Container::setDefaultManager($sessionManager);
                return $sessionManager;
            },
        ),
    );
}

I na sam koniec w metodzie onBootstrap() wywołujemy utworzoną wcześniej metodę: $this->bootstrapSession($e);

W ten sposób możemy używać standardowej sesji w następujący sposób np:

$session = new Container('myContainer');
$session->foo = 'test';
echo $session->foo;

Alternatywne sposoby obsługi sesji

Nie zawsze najbardziej optymalne wydaje się standardowe wykorzystanie sesji. Czasami specyfika aplikacji, architektura, wydajność powodują że standardowe podejście nie wystarcza.
W takiej sytuacji można skorzystać z innych technologi obsługi sesji. W przypadku gdy aplikacja ma strukturę rozproszoną niemożliwe jest wykorzystanie sesji na plikach.
W takiej sytuacji najlepiej skorzystać z obsługi przy pomocy bazy danych. Dokonać tego można w prosty sposób.

Należy utworzyć odpowiednią tabelę w bazie np. za pomocą poniższego polecenia :

CREATE TABLE `my_sessions` (
    `id` char(32),
    `name` char(32),
    `modified` int,
    `lifetime` int,
    `data` text,
    PRIMARY KEY (`id`, `name`)
);

Wystarczy odpowiednio zmodyfikować plik konfiguracyjny aby dołożyć obsługę bazy danych:

return array(
    ...
    'db' => array(
        'driver' => 'Mysqli',
        'host' => 'localhost',
        'dbname' => 'test',
        'username' => 'root',
        'password' => 'mysql',
        'options' => array(
            'buffer_results' => true
        )
    ),
    'service_manager' => array(
        'factories' => array(
            'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
        ),
    ),
    ...
);

a następnie w metodzie getServiceConfig odpowiednio ustawić zmienną $sessionSaveHandler:

$adapter = new \Zend\Db\Adapter\Adapter($config['db']);
$tableGateway = new TableGateway('my_sessions', $adapter);
$sessionSaveHandler = new DbTableGateway($tableGateway, new DbTableGatewayOptions());

pamiętając o dołożeniu odpowiednich deklaracji:

use Zend\Db\TableGateway\TableGateway;
use Zend\Session\SaveHandler\DbTableGateway;
use Zend\Session\SaveHandler\DbTableGatewayOptions;
use Zend\Session\SessionManager;

W tym momencie obsługa sesji zostaje przeniesiona do bazy danych.

Niestety obsługa sesji na bazie danych może nie wystarczyć. Duże obciążenie aplikacji generowane poprzez ruch na stronie może spowodować wąskie gardło dla tak rozwiązanej sesji.
Ratunkiem w tej sytuacji jest skorzytanie z memcache, który jest bardziej wydajny przy analogicznych wymaganiach sprzętowych a umożliwia pracę także w środowisku rozproszonym.

Zastosowanie memacache nie powoduje dużych zmian w naszej aplikacji.

Wystarczy zmodyfikować zmienną $sessionSaveHandler

use Zend\Cache\StorageFactory;
use Zend\Session\SaveHandler\Cache;

$cache = StorageFactory::factory($config);
$sessionSaveHandler = new Cache($cache);

gdzie $config to tablica postaci:

array(
    'adapter' => array(
        'name' => 'memcached',
        'lifetime' => 7200,
        'options' => array(
            'servers' => array(
                array(
                    '127.0.0.1',11211
                )
            ),
            'namespace' => 'myNamespace',
        ),
    )
)

którą można sobie umieścić w pliku konfiguracyjnym, dzięki czemu modyfikacja parametrów będzie bardzo prosta.

Poza przedstawionymi powyżej przykładami rozwiązań obsługi sesji można skorzystać także z innych bardziej zaawansowanych i mniej znanych rozwiązań.

Alternatywnym sposobem korzytania z sesji jest wykorzystanie innych nierelacyjnych baz danych np MongoDb.
Podobnie jak w przypadku powyższych rozwiązań konfiguracja nie jest trudna.

use Mongo;
use Zend\Session\SaveHandler\MongoDB;
use Zend\Session\SaveHandler\MongoDBOptions;
use Zend\Session\SessionManager;

$mongo = new Mongo();
$options = new MongoDBOptions(array(
    'database' => 'mydb',
    'collection' => 'sessions',
));
$sessionSaveHandler = new MongoDB($mongo, $options);

Podobne artykuły

Upload dużych plików w Zend Framework 2 z wykorzystaniem Plupload

Jak rozwiązać wgrywanie plików przez WWW o rozmiarach 1GB i większych.

Wykorzystanie Redis 3 jako systemu cache’ującego w Zend Framework 2

Optymalizacja wydajności aplikacji opartych na Zend Framework 2 z wykorzystaniem Redis.

Poznajmy się
Poznajmy się
Chcesz porozmawiać o start-upach, projektach lub programowaniu?

Hello World! Sp. z o.o.
ul. Twarda 18
00 -105 Warszawa

+48 22 378 47 27
GOGOmedia
GOGOmedia
Internet Software House

Jesteśmy internetową firmą technologiczną, dostarczamy kompletne rozwiązania informatyczne z zakresu web aplikacji. Kompleksowo obsługujemy klientów z różnych sektorów biznesu w zakresie dedykowanego oprogramowania. Prowadzimy szkolenia, doradzamy, wykonujemy specjalistyczne audyty i dzielimy się zdobytą przez lata wiedzą. Dla wielu jesteśmy partnerem, który pomaga osiągać wyznaczone cele biznesowe w najbardziej optymalny sposób.

Polecamy
Polecamy
narzędzia wspierające naszą codzienną pracę
  • New Relic
  • CloudFlare
  • JIRA
  • Bamboo
  • Axure
  • Zendesk
  • Microsoft Project