Пользователь
0,0
рейтинг
3 июля 2008 в 14:17

Разработка → Время жизни сессии

PHP*
Приветствую.
Столкнулся с проблемой убийства сессий раньше назначенного им срока. То есть устанавливаю

ini_set('session.gc_maxlifetime', 120960);
ini_set('session.cookie_lifetime', 120960);


А сессия убивается примерно через 30 минут.
Гуглил долго и тщательно. Не нагуглил ничего, что помогло бы.
Стал читать мануал и нашел причину проблемы. Оказалось всё просто до одурения.


Сайт хостится на виртуальном хостинге и все сессии хранятся в /tmp. Соответственно скрипты других сайтов чистят все сессии по установленному таймауту, который по умолчанию равен 30 минут.
Итак, для того, чтобы избежать такой проблемы надо изменить место хранения сессий — только-то и всего.

ini_set('session.save_path', $_SERVER['DOCUMENT_ROOT'] .'../sessions/');

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

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

UPD:
Суть в том, что все сессии имеют параметр — начало. Когда запускается скрипт — php читает настройку времени жизни (и вероятности запуска сборщика мусора) и запускает сборщик мусора. Если сборщик мусора наткнулся на сессию, которая прожила больше, чем указано в настройках — она удаляется. Удаляется файл с сессией, а кука у юзера, естественно, остаётся. Соответственно, если запустится любой скипт с настройкой времени сессии в 30 минут и при этом он будет искать сессии в той же папке, где расмещает их другой скрипт с большим временем — он удалит ВСЕ сессии, даже те, которые должны прожить больше. Именно для этого надо сменить папку.

Вот что написано в официально мануале по сессиям:
«If different scripts have different values of session.gc_maxlifetime but share the same place for storing the session data then the script with the minimum value will be cleaning the data. In this case, use this directive together with session.save_path.»
Василий Кулаков @coylOne
карма
12,1
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (87)

  • 0
    Т.е. если у какого-то сайта установленно время жизни сессии 5 минут, то и у остальных сайтов сессии будут грохаться каждые 5 минут?
    • 0
      думаю это просто особенность конкретного виртуал-хостинга — время жизни файлов в tmp 30 минут
      • 0
        Тут не в числе дело, а в том, что удаляются сессии по наименьшему таймауту. Если надо увеличить таймаут - надо сменить папку хранения.
    • 0
      Ответил в апдейте
    • +1
      Да. если 5 минут поставить - у всего хостинга будут 5 минут.
      • 0
        Спасибо. Из-за такой казалось бы мелочи можно кучу времени потерять, если не знать заранее.
      • +4
        Поставьте у себя 1 секунду и через день-два хостер выделит каждому отдельную tmp папку :)
        • 0
          Или громко на Вас поматерится || прикроет Ваш аккаунт || поставит минимальное время сессии :)
          • +1
            От такого хостера все-равно лучше уходить.
            • 0
              Не спорю.
  • +5
    Это вы молодец, нестандартные проблемы иногда особенно важны
  • +8
    Это какой-то быдлохостинг
    На нормальных tmp идет как $HOME/tmp, там и сессии лежат
    • 0
      Даже если так, то может встать необходимость иметь, к примеру, два вида сессий - короткие и длинные (запомнить меня). Тогда тоже надо использовать две разные папки для хранения.
      • 0
        "Запомнить меня" в сессии. А может не надо? :)
        • 0
          А где же еще? сессии приятнее всего использовать для авторизации, а где как не в авторизации использовать "запомнить меня"?
          • 0
            Вобщем то Вам ответили, а плодить одинаковые комменты не хочется. Посмотрите чуть ниже в #comment964752 :)
      • –1
        ну для "запомнить меня" вообще используются куки, security key, и прочие фишки. Делать это на сессиях безсмыслено
        • 0
          эм... куки - это лишь часть механизма сессий...
          секьюрити кей - это, я так понимаю, ключ для логина через куку...
          Это все используется при любой авторизации, а "запомнить меня" - это лишь увеличение жизни сессии, ну или куки, если используется самописный механизм "как бы сессий"
          • +1
            да, абсолютно точно
      • 0
        Для "запомнить меня" не используются долгоживущие сессии. Сессия должна работать по принципу "живи быстро - умри молодым" :) Куки с идентификатором сессии в идеале должны иметь нулевое время жизни, то есть до закрытия браузера. Сессия она на то и сессия, что в переводе означает "сеанс".
        "Запомнить меня" лучше реализовывать так: кидать куку в браузер с каким-то ключом, в базе сохранять хеш этого ключа с привязкой к айдишнику юзера. Когда мы видим, что данный юзер не прошел аутентификацию, но у него есть такой ключ в куках, для которого есть хеш в базе, делаем для него автоматический вход, основываясь на айди. Запись из базы удаляем и кидаем ему новый ключ в куки.
        • 0
          Чем в таком случае отличается запись в базе от файла с сессией - не понятно вовсе.
          • 0
            База или файл тут не важно, это проблема реализации/
            Отличие в том, что сессия - это способ сохранять информацию между двумя открытиями страниц. А "запомнить меня" - это автоматическая аутентификация без ввода логина и пароля. Разница в принципе.
            • 0
              Не совсем согласен. Если сессии используются для аутентификации, то как раз "автоматическая аутентификация без ввода логина и пароля" - это и есть "сохранение информации между двумя открытиями страниц". Просто таймаут между этими открытиями несколько больший, чем при использовании сессий для незареганных пользователей.
              • –1
                Нет, это разные вещи, попробуйте понять различие самостоятельно :)
                Немного подскажу: в сессии вы храните просто любые данные, которые нельзя терять между двумя открытиями страницы. "Запомнить меня" - это освобождение пользователя от необходимости при следующем посещении сайта вводить логин-пароль, система делает это как бы за него, но происходит процесс аутентификации, входа в систему, со всеми вытекающими.
                • 0
                  Вот как раз я и говорю, что принципиально это одно и то же. Если использовать сессии для авторизации - то именно по сессии система узнаёт пользователя и понимает, что он авторизован.
                  Это и есть пример того, что вы называете "просто любые данные, которые нельзя терять между двумя открытиями страницы"
                  • 0
                    Нет, еще раз повторю: разные вещи.
                    Можно делать длинные сессии для этого, но это неправильно. Сессия должна жить до закрытия браузера. Кстати, при установке времени жизни куки сессии в 0, в IE (проводил эксперименты, но у же не помню во всех версиях или нет) сессия работает даже при отключенных куках, то есть такие куки IE все же принимает.
                    • 0
                      Вы утверждаете, что это неправильно, но не говорите почему именно. Вот мне лично не ясно.
                      Поясню почему я не вижу ничего в страшного и неправильного в этом - никакого принципиального отличия от вашего предложения: В вашем случае вы хотите хранить соответствие некоего ключа и номера пользователя в базе, а я храню то же самое в файле сессии. При этом я с легкостью могу хранить там неограниченное количество параметров, а вам нужно либо ввобдить поле для сериализованных параметров (считай заново писать phpшные сессии, но уже не на си, а на php =) ), либо для каждого параметра делать отдельное поле.
                      Если сделать хандлер для хранения сессии в БД - то различий нет вообще.
                      Хотя есть одно принципиальное отличие - реализация. Вы хотите потратить время на написание кода, который фактически будет выполнять функции уже реализованные на уровне, с позволения сказать, ядра php.

                      И еще - сессия НЕ обязана жить до закрытия браузера.
                      И еще - в PEAR::Auth классе используются именно сессии. И они не рвутся по закрытию браузера.
                      • 0
                        Вы не поняли. Сессии нужно использовать, не надо ничего переписывать, никакие свои хендлеры не нужны. Но. Сессия - это сеанс. Закончился сеанс - запускай новый. Сеанс не должен быть бесконечно долгим, сеанс, это процесс работы с сайтом на короткое время. В этом принцип работы сессии.
                        Вы же предлагаете использовать длинные сессии для того, чтоб пользователь не вводил заново логин-пароль. А я говорю, что для этого надо сделать систему автоматической аутентификации на основе кука, с заведением новой сессии.
                        Да, топором тоже можно забить гвоздь, но он для этого не предназначен, а есть молоток.
                        Если хотите делать длинные сессии - ну что ж, ваше право, переубедить не могу.
                        Вот, почитайте, на всякий случай:
                        http://phpfaq.ru/sessions
                        • 0
                          Ну статью по ссылке я читал.
                          Переубедить действительно не можете, потому что ни одного конкретного факта, почему именно сессия не может быть долгой, за исключением постоянной аппеляции к переводу слова session.
                          И сессии - это в данном случае не топор, а именно молоток. А ваша "система автоматической аутентификации на основе кука" - это камень.
                          Зачем брать камень и им наживлять гвоздь, если молотком можно и наживить и забить.
                          Если вам необходимо отметить факт того, что пользователь давно не был на сайте - можно хранить в ней время последнего посещения. Пришел пользователь - вы увидели, что его не было к примеру 24 часа, отметили этот факт. Ну если вам так хочется создать новую сессию - перегенерите id уже готовой сессии - будет вам "новая", хотя я никак не пойму, зачем вам это нужно, а обьяснять вы не хотите =)

                          Ну а факт закрытия браузера фиксировать - это паранойя в чистом виде =)
                          • 0
                            Блин, писал-писал и не запостилось...
                            В двух словах. Сессия изначально предназначена для кратковременного хранения данных, чтоб они не пропали при переходе от страницы к странице. Лишнее, устаревшее чистится. В этом предназначение сессии. Представьте, что у вас миллионы юзеров, и в каждой сессии по несколько десятков килобайт данных, и все это хранится в memcache. Спрашивается, зачем хранить все для всех, когда онлайн только 5-6% юзеров, скажем?
                            Но опять же - ваше право поступать как вам вздумается. Уверен, что на многих серьезных проектах сделано по моей схеме. :)
                            • 0
                              Ну вот я и говорю - хранения сессий в БД, как уже было сказано - практика, проверенная на ХайЛоад проектах, но это лишь проблема сториджа, а не принципа. Если все данные хранятся в БД, то никаких проблем с вашим примером не наблюдается =)
                              • 0
                                При высоких нагрузках сессии лучше хранить в памяти. В вашей схеме память будет безбожно забиваться без толку. А если придется перезагрузить зависнувший сервер, скажем - у всех пропадет "запомнить меня". А все почему? Потому что долгосрочное запоминание пользователей - не дело сессий ;)
                                • 0
                                  не согласен с первой фразой. При высоких нагрузках делается балансировка между несколькими серверами. А хранение сессий в памяти делает невозможной такую балансировку.

                                  Собсно неверность первой фразы позволяет не рассматривать дальнейшие =)
                                  • 0
                                    Так же, как для БД выделяется отдельный сервер, так и для memcache выделяют отдельный сервер.
                                    • 0
                                      Но если БД рестартнуть - сессии останутся =)
                                      • 0
                                        А вот если рестартануть memcache, то пропадут. Из этого делаем вывод, что для сессий нельзя использовать memcache?
                                        • 0
                                          почему же, можно, но если хранить сессии в мемкеш, то нужно обеспечить их сохранность. Как это делать - это уже другой разговор - дампами или еще репликацией - это не суть. Суть нашего спора не в мемкеше, а в сессиях =)
                                        • 0
                                          Фактически же вы предлагаете метод "как бы сохранения" сессиий, а точнее их кусочка в БД. То есть по сути из мемкеша вы обеспечиваете частичную копию сессии =)
    • +1
      Да, но два скрипта юзают одну и туже папку, и устанавливают разное время жизни сессий, соответственно, скрипт где меньше время жизни будет с "жадностью" удалять все без исключения сессии не разбирая он их ставил, или нет.
      Это то, как я понял сию статью.
      Мораль. Хочешь юзать разное время жизни - используй разные папки для хранений сессий.
      • 0
        Именно. Плюс еще надо учитывать, что на виртуальных хостингах сессии могут храниться в куче.
        • 0
          ну это уже не суть важно в том случае, если даже твои скрипты юзают разное время жизни.
    • 0
      +1
  • 0
    C ноября 2007...
  • 0
    ...Обычно меясйц, но если есть хвосты, то полугода может длиться.
  • –3
    Ну так надо сначала мануал читать, а потом программировать.
    • +1
      ахахаха =)
      Что называется "всех не перестреляешь".
      Нельзя объять необъятное.
    • +2
      Спасибо, поржал. Вы веб-разработчик? Весь мануал по Апачу прочитали? Все статьи из man по FreeBSD или где у вас сервер? О том, цитируете ли вы спецификацию PHP наизусть, можно даже не спрашивать?
      • +6
        Стараюсь читать мануал ко всем функциям PHP, которые приходится использовать.
        Если уж используешь сессии, то будь любезен прочитать сначала, что пишут сами разработчики, чтоб знать тонкости и подводные камни.
        Так можно по каждой фигне, которую не удосужился прочитать в мане, устраивать гуглинг, а потом постить это на Хабр, как великое открытие.
        • +1
          Я не говорил, что это великое открытие. Просто полезная информация по проблеме, с которой я столкнулся и в сети ответа не нашел.
          А мануал по сессиям я прочел, но вот там есть такая хитрая страничка с перечислением директив php.ini, и именно в ней указан этот аспект. Более нигде об этом не сказано. Не удивительно, что я, как и многие, это упустил из вида.
          • 0
            Понятно, читайте внимательнее в следующий раз.
            Ой, о чем это я, не читайте, конечно, а то тут, я смотрю за рекомендации читать ман перед работой карму в минус загоняют :))
            • 0
              =))))
              Рекомендации и укор - это разные вещи.
              п.с. я никому пока карму не трогал =)
            • 0
              Карма на хабре и веб-разработка разные вещи. Вам не в этот топик
              • 0
                Спасибо, вы такой умный, все разъяснили.
                Я не дрочу на карму, пусть хоть минус бесконечность будет, мне от этого ни тепло, ни холодно, просто ситуация посмешила.
                • 0
                  Да успокойтесь вы. я не со зла. просто уже на самом деле задолбали постоянно все говорить о карме. кругом карма, карма. хрен с ней. тут есть информация. к тому же ценная, и нахрен карму. з.ы. насчет мануалов согласен, но не настолько радикально, все знать невозможно
                  • 0
                    Да я понимаю, что все знать невозможно. Да, наверно, я был слишком резок, просто мне кажется странным создание на хабре топиков с содержимым, которое есть в мануале. Не знаю, мне казалось, что эта ситуация с сессиями "общеизвестна". Видимо, ошибался. Каюсь.
                    • 0
                      Честно говоря об этой проблеме я так же не знал, т.к. храню данные сессий в mysql. а это нужно для общего развития, например для отладки чужого проекта
            • 0
              Общество здесь — это всего лишь модель Большого Настоящего Мира. И здесь точно так же как и Там не любят тех кто безаппеляционным тоном указывает как надо жить другим. Не желая узнать перед этим как эти другие живут и каковы обстоятельства «инцидента».

              Ой, ошибся веткой.
  • –1
    Сначала надо пиво пить, а потом программировать =)
    • +6
      Я бы и сам поставил минус, но это запрещено =)
      • –5
        Хотите я за вас поставлю? ;)
  • +3
    Папку надо сменить не для того, чтобы использовать время жизни. Папку нужно сменить, потому что это дыра: у кого-то постороннего есть доступ к вашим данным. Их можно анализировать, фальсифицировать, что угодно. И раз уж хостер про это не знает, параллельно стоит задуматься, о чем ещё интересном не в курсе тамошние сисадмины.
    • 0
      Это верно. Но и время жизни - важный фактор.
  • +1
    Храните сесси в Бд используя session_set_save_handler(), это даже надежней чем хранить их в memcache используя ini_set('session.save_handler', 'memcache');
    "одобрено хай лоад проектами" (с)
    • 0
      Хорошая идея. Я давно хочу это реализовать, но руки не доходят =)
      • 0
        Наверное время пришло, если болше идей не будет ;)
      • +1
        Ну зачем сидеть и лепить велосипед? http://phpclasses.org вам в помощь чтобы потом на таких мелочах по полдня не тратить.
        • –1
          О0о! спасибо спасибо! не знал про ресурс =)
          Кстати я потратил не пол дня, а два \смущенно трёт ножкой\
        • 0
          а блин ступил. не о том. дада. пол дня на написание хандлеров это не помушски =) да и NIH потом преследовать будет =)
  • 0
    А если и это не помогает и вы пользуетесь Огнелисом, то обратите внимание на about:config - browser.sessionstore.interval
  • 0
    Почитайте про Garbage_Collection... Там все есть...
    Например, тут: http://habrahabr.ru/blog/think_aloud/231…
    • 0
      То что написано там, я и так нагуглил =)
      Тут суть в другом, но все равно спасибо =)
  • +1
    Что же вы стесняетесь? огласите название хостинга, чтобы все знали!
    Зачем скрывать, чтобы кто-то ещё попал? Думаю, что это не так.
  • 0
    мда. Оптимизировал я как-то такие сайты. Суть был в том, что сессии хранились в собственных папках, а чистилась только одна — /tmp. В итоге, время открытия страницы составляло примерно 100мс на неслабеньком проце, сервак просто дымился (при 200 тысячах файлов-то для каждого из 3 хостов, которые там по 2 года лежали).

    После чистки сессий сайты стали открываться по 10мс максимум.

    В общем, добавьте еще один Update про чистку сессий
    • 0
      Не очень понял, что надо добавить +)
      • 0
        что при установке для хранения сессий не директории по умолчанию, ее тоже нужно по крону чистить с заданной частотой, иначе у вас сервер со временем ляжет из-за кастомных директорий
        • 0
          Странно. Все нормально чистится самим php.
        • 0
          нет. все нормально должно чиститься.
          • 0
            если в кроне не стоит, и то и чиститься не будет. Я именно про такие случаи. А в крон после назначения кастомной папки обычно забывают добавить
            • 0
              cron тут не причем, PHP сам с определенной частотой запускает сборщик мусора (см. session.gc_probability, session.gc_divisor), возможно, что параметры были выставлены так, что он никогда не запускался.
              • 0
                Вроде бы на разных системах по-разному. В Debian например чистит cron (думаю это правильно)
          • 0
            хотя, может зависет от настроек PHP: будет ли он проверять, есть ли в папке старые сессии, чтобы их удалить. В таком случае это всегда будет тормозить при большом (от нескольких тысяч сессий) количестве файлов: ведь нам нужно при создании нового файла найти все файлы, которые старше его больше, чем на допустимое время.
  • +3
    я сначало подумал про экзамены, потом подумал что надо заранее сдать зачеты, потом начал читать дальше.. =D
    • +1
      "Время жизни в сессию" =)
    • +2
      Увидел заголовок в гуглридере
      >...Приветствую. Столкнулся с проблемой убийства сессий раньше назначенного им срока. То есть

      пока загрузилась страница - столько успел навыдумывать о сессиях, убийствах и сроках ....
  • 0
    Здорово хранить сессии нескольких приложений в одной папке, особенно если сервер виртуальный и к /tmp имеют доступ все, кому не лень
  • 0
    Можно в придачу добавить собственный обработчик ошибок
  • 0
    Есть еще одна причина пропадания сессий. Сами недавно столкнулись, долго не могли понять, в чем дело. Решение нашлось здесь: http://valera.ws/2008.01.09~cookies/

    Вкратце. Если на странице есть счетчик, устанавливающий куки таким образом: document.cookie=”c=1”;, то в браузере создается отдельная запись для каждого каталога сайта (а с mod_rewrite их может быть сколько угодно). Через некоторое время пул записей в браузере переполняется и первые куки начинают удаляться, грохая соответственно сессию. Выглядит это как разлогинивание юзера в совершенно произвольный момент времени. Исправляется так: document.cookie=”c=1;path=/”;

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