За последние 24 часа нас посетили 22714 программистов и 1219 роботов. Сейчас ищут 667 программистов ...

Сессии в старом memcache

Тема в разделе "Решения, алгоритмы", создана пользователем [vs], 4 ноя 2009.

  1. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    Использование memache для хранения сессий.
    Код (PHP):
    1. <?php
    2. /**
    3.  * @name memses
    4.  * @copyright Vasilii B. Shpilchin (2009)
    5.  * @package GEEG
    6.  * 
    7.  * Memcached-сессии.
    8.  * Элементы сессии хранятся в массиве, записаным одним элементом в memcache.
    9.  * Можно создавать сессии с произвольными именами, но кука автоматически 
    10.  * ставится только для одной сессии!
    11.  */
    12. class memses
    13. {
    14.         // Ресурс соединения с memcached Server
    15.         private static $resource = false;
    16.         // Идентификаторы сессий
    17.         private static $keys = array(false);
    18.         
    19.         /**
    20.          * Инициализация cистемной сессии
    21.          */
    22.         private static function init()
    23.         {
    24.                 self::$resource = new Memcache;
    25.                 $success = self::$resource -> connect(CFG::$mem_host, CFG::$mem_port);
    26.                 if ($success === false)
    27.                 {
    28.                         throw new Exception('memses->init: Невозможно соедениться с memcached Server');
    29.                 }
    30.                 if (key_exists(CFG::$mem_cookie, $_COOKIE))
    31.                 {
    32.                         $exist = self::check($_COOKIE[CFG::$mem_cookie]);
    33.                         if ($exist === false)
    34.                         {
    35.                                 unset($_COOKIE[CFG::$mem_cookie]);
    36.                                 self::restart();
    37.                         }
    38.                         else 
    39.                         {
    40.                                 self::$keys[0] = $_COOKIE[CFG::$mem_cookie];
    41.                         }
    42.                 }
    43.                 else 
    44.                 {
    45.                         self::create();
    46.                         DB::insert('sessions', array('sid','logged'), array(self::$keys[0], 0));
    47.                         setcookie(CFG::$mem_cookie, self::$keys[0]);
    48.                 }   
    49.         }
    50.         
    51.         /**
    52.          * Старт систменой сессии до запросов
    53.          */
    54.         public static function start()
    55.         {
    56.                 self::init();
    57.         }
    58.         
    59.         /**
    60.          * Генератор идентификатора сессии
    61.          * 
    62.          * @return string
    63.          */
    64.         private static function keygen()
    65.         {
    66.                 $letters = array_merge(range('a','z'),range('A','Z'));
    67.                 $letters = array_merge(range(0,9), $letters);
    68.                 $c = 0;
    69.                 while (true)
    70.                 {
    71.                         $key = null;
    72.                         for ($i=0; $i<16; $i++)
    73.                         {
    74.                                 $key .= $letters[rand(0,count($letters)-1)];
    75.                         }
    76.                         if (self::check($key) === false)
    77.                         {
    78.                                 break;
    79.                         }
    80.                 }
    81.                 return $key;
    82.         }
    83.         
    84.         /**
    85.          * Проверка существования и правильности сессии
    86.          * 
    87.          * @param string $sid
    88.          * @return boolean
    89.          */
    90.         public static function check($sid = false)
    91.         {
    92.                 if (!$sid)
    93.                 {
    94.                         $sid = self::$keys[0];
    95.                 }
    96.                 $right = self::get_full($sid);
    97.                 if (is_array($right))
    98.                 {
    99.                         return true;
    100.                 }
    101.                 else 
    102.                 {
    103.                         return false;
    104.                 }
    105.         }
    106.         
    107.         /**
    108.          * Создание сессии
    109.          * 
    110.          * @param string $sid - если не задан, генерируется автоматически
    111.          * @return int $key - идентификатор созданой сессии
    112.          */
    113.         public static function create($sid = false)
    114.         {
    115.                 if ($sid === false)
    116.                 {
    117.                         $key = self::keygen();
    118.                 }
    119.                 else 
    120.                 {
    121.                         $key = $sid;
    122.                 }
    123.                 if (!self::check($key))
    124.                 {
    125.                         $session = array();
    126.                         $session['__create'] = time();
    127.                         $session['__modifed'] = time();
    128.                         $session['__logged'] = 0;
    129.                         $session['__ip'] = $_SERVER['REMOTE_ADDR'];
    130.                         self::$resource -> set($key, $session);
    131.                         $num = array_push(self::$keys, $key);;
    132.                         if ($sid === false && !isset($keys[0]))
    133.                         {
    134.                                 self::$keys[0] = $key;
    135.                                 unset(self::$keys[$num-1]);
    136.                         }
    137.                         return $key;
    138.                 }
    139.         }
    140.         
    141.         /**
    142.          * Установка элемента в сессиию
    143.          * 
    144.          * @param string $key - ключ
    145.          * @param void $value - значение (длина ограничена CFG::$mem_max_lenght)
    146.          * @param string $sid - идентификатор сессии (если не задан - используется системная)
    147.          */
    148.         public static function set($key, $value, $sid = false)
    149.         {
    150.                 if (is_object($value) or is_array($value))
    151.                 {
    152.                         $value = serialize($value);
    153.                 }
    154.                 if (strlen($value) > CFG::$mem_max_lenght)
    155.                 {
    156.                         throw new Exception('memses->set: слишком длиное value: '.$value);
    157.                 }
    158.                 if (strlen($key) > 255)
    159.                 {
    160.                         throw new Exception('memses->set: слишком длиный key: '.$key);
    161.                 }
    162.                 if ($key === '__created' or $key === '__modifed')
    163.                 {
    164.                         throw new Exception('memses->set: нельзя использовать ключи __created и __modifed');
    165.                 }
    166.                 if ($sid === false)
    167.                 {
    168.                         if (self::$keys[0] === false)
    169.                         {
    170.                                 self::init();
    171.                         }
    172.                         $session = self::get_full(self::$keys[0]);
    173.                         $session[$key] = $value;
    174.                         self::$resource -> set(self::$keys[0], $session);
    175.                         self::modifed(self::$keys[0]);
    176.                 }
    177.                 else 
    178.                 {
    179.                         if (!self::check($sid))
    180.                         {
    181.                                 throw new Exception('memses->set: попытка установить значение в несуществующей сессии');
    182.                         }
    183.                         $session = self::get_full($sid);
    184.                         $session[$key] = $value;
    185.                         self::$resource -> set($sid, $session);
    186.                         self::modifed($sid);
    187.                 }
    188.         }
    189.         
    190.         /**
    191.          * Получение элемента из сессии
    192.          * 
    193.          * @param $key
    194.          * @param string $sid - идентификатор сессии (если не задан - используется системная)
    195.          */
    196.         public static function get($key, $sid = false)
    197.         {
    198.                 if ($key == null)
    199.                 {
    200.                         return false;
    201.                 }
    202.                 if ($sid === false)
    203.                 {
    204.                         if (self::$keys[0] === false)
    205.                         {
    206.                                 self::init();
    207.                         }
    208.                         $session = self::get_full(self::$keys[0]);
    209.                         if (key_exists($key, $session))
    210.                         {
    211.                                 return $session[$key];
    212.                         }
    213.                         else 
    214.                         {
    215.                                 return false;
    216.                         }
    217.                 }
    218.                 else 
    219.                 {
    220.                         if (self::check($sid))
    221.                         {
    222.                                 $session = self::get_full($sid);
    223.                                 if ((is_array($session) or is_object($session)) && key_exists($key, $session))
    224.                                 {
    225.                                         return $session[$key];
    226.                                 }
    227.                                 else 
    228.                                 {
    229.                                         return false;
    230.                                 }
    231.                         }
    232.                         else 
    233.                         {
    234.                                 return false;
    235.                         }
    236.                 }
    237.         }
    238.         
    239.         /**
    240.          * Удаление элемента из сессии
    241.          * 
    242.          * @param string $key
    243.          * @param string $sid - идентификатор сессии (если не задан - используется системная)
    244.          */
    245.         public static function del($key, $sid = false)
    246.         {
    247.                 if ($key === '__created' or $key === '__modifed')
    248.                 {
    249.                         throw new Exception('memses->del: нельзя использовать ключи __created и __modifed');
    250.                 }
    251.                 if ($sid === false)
    252.                 {
    253.                         if (self::$keys[0] === false)
    254.                         {
    255.                                 self::init();
    256.                         }
    257.                         $session = self::get_full(self::$keys[0]);
    258.                         if (key_exists($key, $session))
    259.                         {
    260.                                 unset($session[$key]);
    261.                         }
    262.                         self::$resource -> set(self::$keys[0], $session);
    263.                 }
    264.                 else 
    265.                 {
    266.                         $session = self::get_full(self::$keys[0]);
    267.                         if (key_exists($key, $session))
    268.                         {
    269.                                 unset($session[$key]);
    270.                         }
    271.                         self::$resource -> set($sid, $session);
    272.                 }
    273.         }
    274.         
    275.         /**
    276.          * Возвращает массив с номерами и идентификаторами пользовательских сессий за сеанс
    277.          *
    278.          */
    279.         public static function get_user_sessions()
    280.         {
    281.                 $user_sessions = array();
    282.                 foreach (self::$keys as $k => $v)
    283.                 {
    284.                         if ($k !== 0)
    285.                         {
    286.                                 $user_sessions[$k-1] = $v;
    287.                         }
    288.                 }
    289.                 return $user_sessions;
    290.         }
    291.         
    292.         /**
    293.          * Перезапуск сессии
    294.          * 
    295.          * @param string $sid - идентификатор сессии (если не задан - используется системная)
    296.          */
    297.         public static function restart($sid = false)
    298.         {
    299.                 if ($sid === false)
    300.                 {
    301.                         if (self::$keys[0] !== false)
    302.                         {
    303.                                 $sid = self::$keys[0];
    304.                                 self::destroy($sid);
    305.                                 self::create($sid);
    306.                         }
    307.                         else 
    308.                         {
    309.                                 self::init();
    310.                         }
    311.                 }
    312.                 else 
    313.                 {
    314.                         self::destroy($sid);
    315.                         self::create($sid);
    316.                 }
    317.         }
    318.         
    319.         /**
    320.          * Получение всей сессии по идентификатору (если не задан - используется системная)
    321.          * 
    322.          * @param string $sid
    323.          */
    324.         public static function get_full($sid = false)
    325.         {
    326.                 if ($sid === false)
    327.                 {
    328.                         if (self::$keys[0] === false)
    329.                         {
    330.                                 self::init();
    331.                         }
    332.                         $session = self::$resource -> get(self::$keys[0]);
    333.                         return $session;
    334.                 }
    335.                 else 
    336.                 {
    337.                         if ($sid === null)
    338.                         {
    339.                                 return false;
    340.                         }
    341.                         $session = self::$resource -> get($sid);
    342.                         if (is_array($session))
    343.                         {
    344.                                 return $session;
    345.                         }
    346.                         else 
    347.                         {
    348.                                 return $session;
    349.                         }
    350.                 }
    351.         }
    352.         
    353.         /**
    354.          * Уничтожение сессии
    355.          * 
    356.          * @param string $sid - идентификатор сессии
    357.          */
    358.         public static function destroy($sid)
    359.         {
    360.                 if (self::check($sid))
    361.                 {
    362.                         $num = array_search($sid, self::$keys);
    363.                         if (is_int($num))
    364.                         {
    365.                                 self::$resource -> del($sid);
    366.                                 unset(self::$keys[$num]);
    367.                         }
    368.                 }
    369.         }
    370.         
    371.         /**
    372.          * Записывает время изменения сессии
    373.          *
    374.          * @param string $sid - идентификатор сессии (если не задан - используется системная)
    375.          */
    376.         private static function modifed($sid = false)
    377.         {
    378.                 if ($sid === false)
    379.                 {
    380.                         if (self::$keys[0] === false)
    381.                         {
    382.                                 return false;
    383.                         }
    384.                         else 
    385.                         {
    386.                                 $sid = self::$keys[0];
    387.                         }
    388.                 }
    389.                 $session = self::get_full($sid);
    390.                 if ($session)
    391.                 {
    392.                         $session['__modifed'] = time();
    393.                         self::$resource -> set($sid, $session);
    394.                 }
    395.                 else 
    396.                 {
    397.                         return false;
    398.                 }
    399.         }
    400.         
    401.         /**
    402.          * Обновляет информацию о сессии в БД.
    403.          * Доступно только для системной сесии.
    404.          */
    405.         public static function update()
    406.         {
    407.                 if (!self::check(self::$keys[0]))
    408.                 {
    409.                         self::init();
    410.                 }
    411.                 $where = array();
    412.                 $where[0] = array('`sid`='=>self::$keys[0]);
    413.                 DB::update('sessions', array('logged'), array(self::get('__logged')), $where);
    414.         }
    415.         
    416.         /**
    417.          * Сохраняет sid пользовательской сессии в БД.
    418.          * 
    419.          * @param string $sid - индентификатор сессии
    420.          */
    421.         public static function save_user_session($sid)
    422.         {
    423.                 if (!self::check($sid))
    424.                 {
    425.                         throw new Exception('memses->save_user_session: несуществующая сессия не сохранена.');
    426.                 }
    427.                 else 
    428.                 {
    429.                         $table_exist = DB::mem_check(CFG::$user_sessions);
    430.                         if ($table_exist === false)
    431.                         {
    432.                                 $cols = array('sid');
    433.                                 SYS::init_memory_db(CFG::$user_sessions, $cols);
    434.                         }
    435.                         $fields = array('sid');
    436.                         $values = array($sid);
    437.                         DB::mem_insert(CFG::$user_sessions, $fields, $values);
    438.                 }
    439.         }
    440. }
    441. ?>
    Основная (в комментариях - системная) сессия инициализируется при первом использовании (или явно методом start()), получая sid из куки или генерируя новый. Можно инициализировать больше сессий, с задаными номерами или сгенерироваными автоматически. Сохранять их sid'ы придется тоже вручную (метод save_user_session для сохранения в БД в таблицу типа memory требует других классов :).
    Недостаток - чтоб работало, надо после всех действий делать апдейт (метод update, а в нем обращение к БД). Это тоже была таблица типа memory.
    Пример использования:
    Код (PHP):
    1. memses::set('logged', 1);
    2. memses::update();
    3.  
    4. memses::create('mysession');
    5. memses::set('name', 'Vasya', 'mysession');
    6. memses::save_user_session('mysession');
    7.  
    8. $more = memses::create();
    9. memses::set('key', 'value', $more);
    10. memses::save_user_session($more);
    11.  
    В ПРИМЕРЕ исправлена ошибка.
     
  2. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    сам писал?

    а если куки выколючены?
     
  3. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    Всё сам писал, вначале года.
    Если куки выключены, тогда только вручную создавать и сохранять куда-нить. Можно, кстати, стартовать обычную сессию, только ради идентификатора в урле.
     
  4. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    1) можно использовать ArrayAccess
    2) session_set_save_handler
     
  5. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    Вот когда я это писал, не знал про ArrayAccess. Но опять же тогда придется отказаться от статики, а значит надо будет делать синглтон, и в каждом классе, методе или функции создавать лишнюю переменную.
     
  6. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    кроме того: чем плох md5/sha1 от microtime(true) ? меньше ж кода, нет циклов шаманских.
    и я бы предложил более высокий уровень абстракции, использовать какую-нить прокладку Cache, в которой можно выбрать с чем работаем (тот же мемкеш, новый мемкешед, апц, иксКэш)

    кому-то удобно создавать +1 переменную
     
  7. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    Идея клевая. Кода не хваеатет)
     
  8. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    А кто-нибудь проверял, что быстрее будет memcached или хранение обычных сессий в памяти (если не узкаывать путь к сессиям, то они хранятся в памяти)?