2010-01-06 20 views
32

Tengo una configuración de sitio que, al cargar la página, convierte todas las cadenas enviadas por el usuario en objetos SafeString. Para aquellos que no están familiarizados con SafeString, básicamente obliga al usuario a hacer eco de datos desinfectados que previenen XSS y otras cosas ...

De todos modos, hay un problema. Mi matriz $ _SESSION se está llenando con __PHP_Incomplete_Class Object. Según lo que he leído, esto se debe a que no se inicializó la clase antes de la sesión y luego se almacenaron los objetos de la clase en la sesión.

Aquí está mi código:

require_once __WEBROOT__ . '/includes/safestring.class.php'; 

$temp = array 
(
    &$_SERVER, &$_GET, &$_POST, &$_COOKIE, 
    &$_SESSION, &$_ENV, &$_REQUEST, &$_FILES, 
    &$HTTP_SERVER_VARS, &$HTTP_GET_VARS, 
    &$HTTP_POST_VARS, &$HTTP_COOKIE_VARS, 
    &$HTTP_POST_FILES, &$HTTP_ENV_VARS 
); 

function StringsToSafeString(&$array) 
{ 
    foreach ($array as $key => $value) 
    { 
     if (is_string($array[$key])) 
     { 
     $array[$key] = new SafeString($value); 
     } 

     if (is_array($array[$key])) 
     { 
     StringsToSafeString($array[$key]); 
     } 
    } 
} 

StringsToSafeString($temp); 

unset($temp); 

No puedo pensar en una manera de volver a escribir esto que resolvería el problema:/

¿Alguna idea?

Respuesta

56

Cuando accede a $_SESSION, no solo está cambiando la copia del script actual de la lectura de datos de la sesión, está escribiendo objetos SafeString en la sesión activa.

Pero colocar objetos personalizados en la sesión es dudoso y es algo que generalmente trataría de evitar. Para poder hacerlo, debe haber definido la clase en cuestión antes de llamar al session_start; si no lo hace, el manejador de sesión de PHP no sabrá cómo deserializar las instancias de esa clase, y terminará con el __PHP_Incomplete_Class Object.

Así que evite dejar la sesión. Si debe seguir este enfoque, haga una copia de los datos del $_SESSION en una matriz local $mysession. Sin embargo, debo decir que creo que la idea de SafeString es peligrosa e inviable; No creo que este enfoque sea siempre hermético. Si una cadena de texto sin procesar es 'segura' no tiene nada que ver con su origen, es una propiedad de cómo la codifica para el contexto de destino.

Si obtiene otra cadena de texto de una fuente diferente, como la base de datos o un archivo, o calculada dentro del script, necesita exactamente el mismo tratamiento que una cadena que proviene del usuario: necesita ser htmlspecialchars Ed. Vas a tener que escribir ese escape de todos modos; la red segura no te gana nada. Si necesita enviar la cadena a un formato de destino diferente, necesitaría un escape diferente.

No puede encapsular todos los problemas de procesamiento de cadenas en una sola caja práctica y nunca pensar en ellas de nuevo; así no es cómo funcionan las cuerdas.

+0

¡¡Gran respuesta !!! –

+0

Gran respuesta. +1. Me encanta PHP: D Mi problema era un viejo archivo de caché. Supondríamos un mensaje de error como: "El objeto no se pudo deserializar, porque no se pudo encontrar" ... –

+1

"requiere la clase ANTES de llamar a session_start()" – max4ever

6

Sólo hay que incluir el safestring.class.php antes de llamar session_start() cuando se quiere leer los objetos SafeString de $_SESSION variables:

<?php 

require_once __WEBROOT__ . '/includes/safestring.class.php';  
session_start(); 

print_r($_SESSION); 

y sí, si está utilizando framework PHP que (probablemente) llama session_start() internamente, asegúrese de require_once el archivo de clase de antemano (use ganchos o los mecanismos que proporciona el marco).

2

La respuesta de Lukman es correcta. Pero ya lo mencionas en tu pregunta, por lo que aparentemente no puedes crear una instancia de la clase antes de que comience la sesión, por alguna razón.

Es posible que desee comprobar si las sesiones se inician automáticamente en el php config: http://www.php.net/manual/en/session.configuration.php#ini.session.auto-start

Si son y Yu puedo evitar eso, es posible que desee comprobar si puede tener sus clases autocargado antes de eso: http://php.net/manual/en/language.oop5.autoload.php

Si todo lo demás falla, todavía se puede serializar los objetos antes de almacenarlos en una sesión, y les unserialize cada uno de ellos que se recupere: http://php.net/manual/en/function.serialize.php

Pongo t ver en el código donde se almacenan las variables, pero sería algo así como

$mystuff = unserialize($_SESSION["mystuff"]); 
$mystuff->dostuff(); 
$_SESSION["mystuff"] = serialize($mystuff); 

Asegúrese de cargar la definición de clase antes de unserialize sus variables

$ 2c, * -pike

3

Acabo de resolver algo como esto. Me tomó horas para finalmente encontrar cómo mi orden fue jodida.

Tengo un archivo que se llama de forma asíncrona.

myFile.php

ese archivo contenía la siguiente ..

$result = include ("myOtherFile.php"); 
return $result; 

Myotherfile.php tiene algo como esto

require_once "lib/myClassLibs.php"; 
require_once "webconfig.php"; 

la webconfig.php tenía el session_start() en eso.

La lib/myClassLibs tiene toda la información de clase init. Si marca antes de la llamada webconfig, puede ver que la clase está disponible.

Si marca antes de la llamada webconfig, también verá que la sesión ya ha comenzado. Si comprueba antes lib/myClassLibs.php, verá que la sesión ya se inició.

Comprobando en myFile.php antes de incluir MyOtherFile.php, encuentra que la sesión no ha comenzado.

Esto representa el código heredado que ha funcionado durante los últimos 8 años sin que yo haya tenido problemas con él. Saqué el include de "MyOtherFile.php". Ahora mis sesiones están sincronizando correctamente.

-2

Usted sólo puede estar llamando,

session_start(); 
session_start(); 

dos veces en su código. Llámalo una vez. Verifica las clases de PHP requeridas para las repeticiones. Esta fue la solución para mí.

+3

Llamar 'session_start' dos veces no causa el problema . No tener la clase necesaria cargada causa el problema. – Charles

1

He resuelto este problema al incluir la función __autoload en la parte superior de mi archivo php. Por lo que se ve así:

<?php 
require_once("path/to/include.inc"); 

//Needed for serialization/deserialization 
function __autoload($class_name) { 
    include "path/to/". $class_name . '.php'; 
} 

En PHP 5, ¿no serán necesarios esta función, pero me he quedado atrapado hasta que use esta función. ¡Espero que esto ayude a alguien más!

+0

La carga automática (o la carga explícita, que no deseará en PHP moderno) siempre es necesaria cuando una clase se extraterritorializa de los datos '$ _SESSION'; esto no tiene nada que ver con la versión de PHP utilizada ... puede hacerlo ' t desserializar una clase, si esa clase no puede cargarse (o no está cargada), por lo tanto, usted obtiene '__PHP_Incomplete_Class' para cualquier cosa que no haya podido cargar automáticamente. –

1

Resolví el problema usando la función json_encode y json_decode.

Aquí es donde quería asignar el valor a la sesión.

$user_json    = json_encode($user); 
$_SESSION['user']   = $user_json; 

Esto es donde muestro el usuario después de la decodificación de la JSON

session_start(); 

$user_json= $_SESSION['user']; 
$user = json_decode($user_json); 

Esto resuelve mi problema, pero no estoy seguro sobre el rendimiento o la seguridad. No los he comprobado.

+0

Gracias, esta solución parece la más fácil, especialmente para mi pequeña clase/objeto. ¿Alguien puede decirme si hay algún problema de seguridad con esto? –

19

Sé que han pasado años desde que se me preguntó esto, pero estoy publicando mi respuesta porque ninguna de las respuestas anteriores realmente explica al OP lo que está realmente mal.

PHP serializa sus sesiones utilizando los métodos integrados serialize y unserialize. serialize de PHP tiene la capacidad de serializar objetos de PHP (también conocidos como instancias de clases) y convertirlos a cadenas. Cuando unserialize esas cadenas, las convierte de nuevo esas mismas clases con esos valores. Las clases que tienen algunas propiedades privadas y desean codificar/decodificar eso o hacer algo complejo en su serialización/deserialización implementan la clase Serializable y agregan los métodos serialize y unserialize a la clase.

Cuando unserialize intentos de PHP para unserialize un objeto de clase, pero el nombre de la clase no se declara/necesario, en lugar de dar una advertencia o lanzar una Exception, que la convierte en un objeto de __PHP_Incomplete_Class.

Si no desea que sus objetos de sesión se conviertan a __PHP_Incomplete_Class, puede hacerlo requiriendo los archivos de clase antes de invocar session_start, o registrando una función de autocarga.

+0

** ProTip: ** si la solución no parece funcionar, recuerde borrar la sesión/cookie de sesión/probar en una ventana de navegación privada. Perdí el tiempo depurando porque olvidé que los objetos '__PHP_Incomplete_Class' ya habían sido almacenados en la sesión, ¡do! – Pocketsand

+0

Si usa SPL, ¿funcionaría? (Todavía no implementado, pero eventualmente) –

0

Mi error aquí fue que configuré la configuración session.auto_start en on. La sesión se inicializaría antes de que se invoque cualquier línea de código (incluido el autocargador).

Cuestiones relacionadas