2011-09-21 26 views
7

Tengo problemas con el sitio PHP que ejecuto en el trabajo donde los usuarios se desconectan después de unos minutos (el tiempo exacto varía, pero es lo suficientemente frecuente como para ser un problema), independientemente de si han estado utilizando activamente el sitio o no.Sesiones PHP que caducan temprano

La dificultad es que no puedo reproducir este problema, si inicio sesión como los mismos usuarios que usan el mismo navegador no me desconecto, lo que sugiere que no es un caso de que el sitio se rompa por completo. Lamentablemente, no tengo acceso a las máquinas de los usuarios para ejecutar ningún software de detección de tráfico.

Las cosas ya he controladas son:

  • pidiendo a los usuarios a probar diferentes navegadores. Esto no parece resolver el problema y no es una solución a largo plazo, ya que no puedo determinar qué navegadores usarán los clientes.
  • La hora del servidor es correcta y en línea con las máquinas del usuario.
  • El usuario Apache se ejecuta como tiene permiso para escribir en la carpeta de la sesión, y puedo ver los archivos de sesión que se están creando y sus tiempos de modificación actualizados.
  • No se están utilizando funciones de búfer de salida.
  • El problema ocurre en una variedad de páginas que parecen no tener nada en común (es decir, no es que todas ellas utilicen AJAX, ni actualicen la base de datos ni ninguna otra razón).
  • Los usuarios solo acceden a su cuenta desde una máquina, es decir, no hacen un poco de trabajo en su computadora portátil, cambian al escritorio y luego se preguntan por qué han cerrado sesión en su computadora portátil (no permitimos múltiples inicios de sesión simultáneos para el mismo usuario).

Los ajustes de sesión en PHP son los valores predeterminados de Debian, y no se han cambiado en un archivo .htaccess ni en ningún otro lugar. Los principales son:

session.cookie_lifetime 0 
session.gc_divisor 100 
session.gc_maxlifetime 1440 
session.gc_probability 0 
session.save_handler files 
session.save_path /var/lib/php5 
session.use_cookies On 

Debian borra las sesiones a través de una tarea programada en lugar de usar recolector de basura de PHP, por lo que gc_probability se pone a 0. La versión de PHP nos estamos quedando es: PHP 5.2.6-1 + lenny13 con Suhosin-Patch 0.9.6.2 (cli) (última versión en Lenny, estaremos actualizando a Squeeze pronto, pero no creo que esa sea la causa del problema).

Usamos Zend_Session para gestionar sesiones, y una instancia de Zend_Session_Namespace se crea una vez en cada página, llamando automáticamente a session_start(). Las sesiones se borran llamando Zend_Session :: destroy() en la página de cierre de sesión, por lo que las únicas formas en que un usuario debe haber iniciado a cabo son:

  • Si hacen clic explícitamente el enlace de desconexión (log que cuando esto sucede y que doesn Parece que la navegación es precargar la página y, por lo tanto, cerrar la sesión del usuario).
  • Si dejan la sesión inactiva durante más de 24 minutos, en ese momento Debian probablemente eliminará su sesión (hay una tarea cron que se ejecuta cada media hora eliminando todas las sesiones que no se han modificado durante más de 24 minutos).
  • Si cierran el navegador, se borrará su cookie de sesión con un tiempo de caducidad de 0.

Las comprobaciones para ver si un usuario está conectado son:

  • Ellos tienen una sesión válida (comprobado por ver si se puede acceder a $ zsession-> user_id).
  • Hay una fila en la tabla de sesiones que tiene un ID de usuario y una ID de sesión coincidentes, y esta última se actualizó hace menos de una hora. Borramos esta fila al cerrar la sesión de modo que incluso si la sesión todavía existe en el disco, nadie puede acceder a esa cuenta sin necesidad de acceder.

¿Puede alguien sugerir otras cosas que pueda intentar?

Editar: Algunas cosas adicionales que he probado en base a los comentarios restante:

  • Configuración session.cookie_domain: Esto parece tener un comportamiento muy extraño en PHP. Si no configuro esta variable y la dejo como predeterminada de '' (cadena vacía), una solicitud de www.domain.com generará una cookie de www.dominio.com. Sin embargo, si configuro cookie_domain a 'www.dominio.com', el dominio de la cookie es '.www.domain.com' (aviso de punto líder, que significa válido para todo lo que se encuentre debajo de www.dominio.com, por ejemplo, subsitio.www .dominio.com).
  • Configuración de session.cookie_lifetime: PHP no parece actualizar el tiempo de caducidad en cada solicitud, por lo que si configuro cookie_lifetime a 3600 la cookie caducará una hora después de que el usuario visite el sitio por primera vez, incluso si inician sesión y constantemente lo usan .

Edición 2: Sobre la base de otras cosas que la gente ha preguntado:

  • El sitio está alojado en un centro de datos, en una VLAN separada. Nadie que acceda al sitio está en la misma red que el sitio.
  • No se utiliza la autenticación IP ni la dirección IP del cliente en ninguna parte del proceso de la sesión (por ejemplo, no adjuntamos la sesión a una dirección IP y bloqueamos al usuario si su siguiente solicitud proviene de un IP diferente).
+0

La última vez que tuve un problema similar, me olvidé de manejar las sesiones correctamente en cierto archivo php (todos los otros archivos estaban bien). El resultado fue que la sesión se volvió inválida después de que el usuario intentó abandonar esa determinada página, por lo que se desconectó después de diferentes tipos de minutos, dependiendo de cuándo navegaba a la página. No veo esto como una solución. Véalo como una pista donde podría buscar algunos errores. ¡Buena suerte! ^^ – Marco

+0

Las zonas horarias (o el horario del servidor incorrecto) pueden causar problemas en algunos casos. – Smar

+1

@Smar Es posible, pero dije explícitamente 'La hora del servidor es correcta y está en línea con las máquinas del usuario'. – pwaring

Respuesta

1

Al final, la respuesta fue simplemente el desguace de sesiones y escribir mi propio código de galletas muy simple que se diferencia de las sesiones de las siguientes maneras:

  1. Tiendas de un hash (poco como un identificador de sesión) en el base de datos en lugar de en archivos.
  2. Establece que la cookie caduque en 3600 segundos a partir de ahora (actualizada en cada página) en lugar de 0 segundos (esta última parecía causar problemas para los usuarios de IE, aunque nunca podría replicarla).
  3. Solo envía el encabezado de la cookie cuando el usuario inicia sesión o inicia sesión.

No es una situación ideal ya que hay algo de reinvención de la rueda, pero mi pequeña solución parece funcionar donde las sesiones de PHP no lo hicieron, y tener un sitio de trabajo es lo más importante.

0

es su sitio en diferentes dominios? por ejemplo domain.com, www.domain.com, subdomain.domain.com? si algunas páginas se redireccionan a un dominio diferente (www se considera un subdominio que es diferente) las sesiones no funcionarán cuando la dirección cambie

EDITAR: Debe reproducir el problema. Pregúnteles a sus clientes qué tipo de navegador utilizan, qué acción hacen hasta que se realicen, ¿están viendo la misma dirección IP para el sitio que usted? (Es decir, ambos están en redes externas o ambos en la misma red con el sitio)

Cuando logre encontrar el problema, verifique los encabezados de solicitud/respuesta cuando funcione la sesión, y también cuando no funcione y luego compara

+0

PHP realmente configurará la cookie de sesión para todos los subdominios: 'Set-Cookie \t PHPSESSID = 0a4ogbefeptfndukol3pjl7tg4; ruta = /; domain = .thesite.com'. Tenga en cuenta el punto delante del nombre de dominio. –

+0

En realidad, PHP no establece la cookie de sesión para todos los subdominios: Set-Cookie: PHPSESSID = 428d4be9caca21acc558c0510f22717b; ruta = /; secure Si miro la cookie en Firefox, está configurada para www.domain.com (redirigiremos cualquier solicitud de domain.com a www.domain.com). – pwaring

+0

¿Qué versión de PHP estás usando porque en el mío el resultado anterior es visible? –

0

su session.gc_maxlifetime se establece en 1440 ms, que es solo 1,44 segundos. ¿No debería ser 1440000 ms = 24 minutos?

+1

'session.gc_maxlifetime' se establece en segundos. Entonces 1440 por 24 minutos es correcto. – Marco

+1

¿Estás seguro de que no hay otras secuencias de comandos con una menor duración de la sesión? porque el script con la vida más baja se ejecuta. –

+1

gc_maxlifetime se establece globalmente y no se reemplaza en ninguno de los scripts de PHP. Todas las funciones de manejo de sesión se realizan en un archivo que se incluye en cada página. – pwaring

0

Puede intentar configurar session.use_only_cookies a un valor de 1 y session.cookie_lifetime a un valor de 1440 segundos.

+0

para 'session.cookie_lifetime' 0 significa el navegador para eliminar la cookie cuando se cierra su ventana, que para la cookie de sesión es ideal. –

+1

Claro que es ideal, pero por ejemplo si está trabajando bajo un controlador de dominio de Windows que establece derechos específicos para los navegadores, no se debe garantizar que la regla funcione. Tuve el problema bajo un controlador de dominio de que una ventana emergente dentro de la misma sesión destruía la cookie de sesión. Después de establecer el tiempo de vida de manera explícita, pude resolver este problema. – Marco

+0

No he oído hablar de ese problema de controlador de dominio, creo que esa podría ser la solución. Lo probaré y veré qué sucede, aunque no estoy seguro de si PHP actualiza la cookie de sesión en cada carga de página, por lo que existe el riesgo de que caduque después de 24 minutos, incluso si el usuario aún está activo. – pwaring

3

Debian elimina a través de sesiones de una tarea programada en lugar de usar recolector de basura de PHP

Eso es muy extraño - y lo que es el código que se ejecuta en el trabajo de cron?

Borramos esta fila al cerrar la sesión

le sugiero que tenga esto para, por ejemplo, 2 días después de la sesión ha expirado/se suprime (pero marcarlo como muertos en el punto donde se encuentra actualmente borrar eso). Además, comience a registrar la identificación de la sesión en los registros de su servidor web.

+0

No es particularmente extraño, Debian ha usado ese método por años. El código real es: 09,39 * * * * raíz [-x/usr/lib/php5/maxlifetime] && [-d/var/lib/php5] && find/var/lib/php5/-type f -cmin + $ (/ usr/lib/php5/maxlifetime) -delete – pwaring

+0

y ha verificado qué salidas/usr/lib/php5/maxlifetime? – symcbean

+0

Sí, produce 24 (que es lo que esperaba). El trabajo cron definitivamente está funcionando correctamente y solo borra archivos de sesión a los que no se ha accedido durante 24 minutos. – pwaring

1

creo que cuentes cambiar el valor de

session.gc_maxlifetime 

también me enfrenté al mismo problema. Pasé mucho tiempo en él, entonces le pregunté a mi proveedor de servicios web y, al obtener el permiso, cambió ese valle. Ahora funciona bien.

+0

Ya está configurado en 1440 segundos, o 24 minutos, pero los usuarios están cerrando sesión mucho antes. – pwaring

1

¿Hay otras aplicaciones de php que se ejecutan en el mismo sistema (por ejemplo, bajo diferentes hosts, por ejemplo?)? ¿También están guardando sesiones en/var/lib/php5?

Si es así, y una de esas aplicaciones tiene un bajo umbral de recolección de basura, eliminarán los archivos de sesión de su aplicación.

Hago mucho desarrollo de ZF, y si uso sesiones basadas en sistemas de archivos, las incluyo en la aplicación/datos/sesión en lugar del sistema predeterminado.

+0

Solo hay una aplicación en el sistema, aparte de un par de sitios de prueba, pero todos tienen el mismo umbral de GC. – pwaring

0

Al final opté por enviar un encabezado Set-Cookie en cada solicitud de página, similar a lo que FlyBy sugirió en uno de los comentarios. El código/lógica relevante es ahora (suponiendo session_start() ya ha sido llamado):

$this->session_name = session_name(); 
$update_cookie = isset($_COOKIE[$this->session_name]); // Check if cookie already set, as PHP will send the first Set-Cookie when the session is started 
$this->logged_in = $this->checkSession(); // Function which checks whether a valid (i.e. not timed-out) session row exists in the DB 
if ($this->logged_in) { 
    $this->updateSession(); // Update the session row to the current time 

    if ($update_cookie) { 
    // Update the cookie expiry only if it existed before the login check 
    setcookie($this->session_name, $_COOKIE[$this->session_name], $this->time + 3600, '/'); 
    } 
} 

No estoy seguro de por qué esto funcionó, pero no he tenido ninguna queja más y el número de inicios de sesión se ha reducido drásticamente (ya no hay varios inicios de sesión en los registros para el mismo usuario en pocos minutos el uno del otro).

Sin embargo, probablemente reescribo el código en algún momento solo para usar una fila de base de datos y una cookie en el cliente, porque la funcionalidad de sesión en PHP tiene tantas variables que es extremadamente difícil determinar qué causa el problema , y el manejo de la cookie de sesión es ligeramente diferente a cómo se manejan las cookies normales. En particular, debe tener cuidado con la función setcookie, porque la ruta predeterminada para las cookies de sesión iniciadas por PHP es '/', pero el valor predeterminado para setcookie es la ruta actual del directorio, y estas no serán necesariamente las mismas.

+0

Deseche eso, aparentemente el problema todavía está sucediendo, y me he quedado sin ideas. – pwaring