2013-07-31 12 views
5

Perché UnexpectedValueException viene generato in session_start()?UnexpectedValueException in session_start() php non riuscito serializzazione SPLObjectStorage

devo oggetto che ha la proprietà di SPLObjectstorage. Tale oggetto è assegnato alla sessione come

Sospetto che la sessione interna serializzi il problema di fronte per decodificarlo. Memorizzo la sessione nel database e sembra che stia serializzando lo objectStorage ma non possa decodificarlo.

dati di sessione Esempio

self|O:4:"User":8:{s:5:"�*�id";N;s:7:"�*�nick";N;s:13:"�*�reputation";i:1;s:11:"�*�password";N;s:8:"�*�email";N;s:7:"�*�crud";O:10:"CRUDobject":2:{s:13:"�*�fieldCache";a:0:{}s:13:"�*�dependency";r:1;}s:7:"�*�auth";N;s:11:"�*�roleList";C:11:"RoleStorage":23:{x:i:1;N;,r:13;;m:a:0:{}}} 

Rolestorage è estende su SPLObjectstorage session_decode() sul sopra stringa restituisce anche false tutte le idee?

rimuovere l'attributo roleList rende serializzare correttamente.

Se io faccio parte

$sr = serialize($roles); // $roles is RoleStorage object 
var_dump($sr); 
var_dump(unserialize($sr)); 

Esso stampa string 'C:11:"RoleStorage":22:{x:i:1;N;,r:3;;m:a:0:{}}' (length=46) e poi viene a mancare con lo stesso messaggio, mentre deserializzazione. Non ho idea del perché questo sta accadendo.

Nota: durante il collegamento dell'oggetto a RoleStorage ho utilizzato l'oggetto stesso come dati. Significa che è memorizzato come riferimento. Non so come (se) fa serialize() gestisce internamente questo.

+0

Si prega inoltre di aggiungere un [hexdump dei dati della sessione] (http://stackoverflow.com/questions/1057572/how-can-i-get-a-hex-dump-of-a-string-in -PHP). Anche la 'UnexpectedValueException' ha un messaggio. La tua domanda non contiene quel messaggio finora, per favore aggiungilo. Spesso contiene informazioni importanti sul problema quando non è serializzato. – hakre

risposta

2

non ho idea perché questo sta accadendo

Nella vostra versione di PHP e con lo script di cemento non è possibile serializzare un oggetto basato su SPLObjectStorage a meno che non si prenda cura della serializzazione. Se vedete questa parte della stringa serializzata:

C:11:"RoleStorage":23:{x:i:1;N;,r:13;;m:a:0:{}} 

Questo rappresenta l'oggetto RoleStorage. La grande C all'inizio stands for:

C - oggetto che implementa serializeable Interface

Così l'oggetto stesso è responsabile qui circa la serializzazione e deserializzazione. Normalmente puoi aspettarti che funzioni, ma non tutto il software è privo di bug.

Nel tuo caso sembra che PHP abbia fatto un errore. Il formato interno ecco:

x:i:1;N;,r:13;;m:a:0:{} 
     ^^^^^^^ 

E il problema è nella posizione evidenziata, ciò richiede un oggetto serializzato, non NULL. E non è virgola-terminato con un riferimento (r:13 qui), ma con null (N) per funzionare.

Quindi sembra un hick-up attivato facendo riferimento ad alcuni oggetti precedenti (fare attenzione che questo riferimento non sia lo stesso di riferimenti/alias variabili in userland PHP).

Quindi come andare avanti?

È ora di iniziare a isolare il problema e creare un esempio autonomo e riproducibile.Questo è necessario per esaminare ulteriormente il problema così come lo vedi. Questo è importante per due motivi:

  1. Se si tratta di un bug in PHP, esso devono essere segnalati, un test di regressione scritto e aggiunto al PHP Q & A e poi il bug fisso (se non ancora fissato).
  2. Se si sta cercando una soluzione alternativa, è necessario riprodurre il problema originale per creare una soluzione rapida e semplice.

Ho eseguito alcuni test per un work-around, tuttavia finora non sono in grado di riprodurre il problema, quindi non posso davvero suggerire come risolvere il problema perché non lo ho qui.

+0

+1 Avevo provato a trovare la risorsa sulla notazione di serializzazione ma non riuscivo a trovarla in PHP DOC. Dovrebbero averlo aggiunto lì. – varuog

+0

Attualmente ho sostituito SPLObjectStorage con una classe astratta che utilizza la matrice per archiviare i dati e segue la stessa interfaccia di SPLobjectStorage come soluzione temporanea. Una volta che ho isolato e risolto il problema, come hai detto, avrei semplicemente cambiato la Base Abstract Class con SPLObjectStorage – varuog

1

C'è stato un bug chiuso di recente per un problema simile a questo. A seconda della versione di php che stai utilizzando, potresti comunque essere interessato. La versione interessata è 5.3.15.

Estratto:

[2012-07-27 16:08 GMT] dot j henge-Ernst a interexa dot de

Il problema è che l'unserialize di ArrayIterator (e anche forse ArrayObject o altre classi SPL) non possono dereferenziare oggetto riferimenti .

Se si è interessati da questo errore, è possibile che sia correlato al dereferenziamento. Forse prova una nuova versione di PHP per vedere se succede ancora.

+0

Sto usando php 5.4.3 che il bug è stato segnalato per "Lo stesso comportamento con PHP 5.4.5'. Credo che potrei essere interessato. Anche se il changelog di http://php.net/ChangeLog-5.php non risolve il bug, non capisco perché? Sai quale versione sarebbe sicura usarla? – varuog

+0

Ho perso il riferimento a 5.4.5. Buona pesca. Sembra che la correzione sia stata commessa solo circa 6 settimane fa, quindi potrebbe non esserci ancora una versione ufficiale con la correzione. Potrebbe essere necessario compilare dal sorgente se hai veramente bisogno di questa funzionalità. http://git.php.net/?p=php-src.git;a=commit;h=04db57066deb73ef9c960a2c5bebad49195bc1bb –

3

oggetti con il nome RoleStorage solleva un paio di bandiere per me. Spesso, questo oggetto contiene una risorsa di ordinamento o un riferimento a un oggetto PHP incorporato. Le risorse non possono essere serializzate, né alcuni tipi built-in PHP possono essere serializzati. Considera l'implementazione dei metodi magici __sleep e __wakeup in questi casi.
Diciamo che avete un riferimento PDO qualche nell'oggetto RoleStorage, allora queste proprietà magiche potrebbe essere simile a questa:

public function __sleep() 
{ 
    $this->pdo->commit();//commit && close 
    $this->pdo = array($dsn, $user, $pwd, array(
               PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION 
             ) 
    ); 
    return serialize($this); 
} 
public function __wakeup() 
{ 
    $this->pdo = new PDO($this->pdo[0], $this->pdo[1], $this->pdo[2], $this->pdo[3]); 
} 

Ma dal momento che si dice gli RoleStorage oggetti è un bambino di SPLObjectStorage, si starebbe meglio sovrascrivendo implementazione s' il SPLObjectStorage di the Serializable interface:

non è possibile per __sleep() per restituire i nomi di proprietà private nelle classi genitore. In questo modo si verificherà un errore di livello E_NOTICE. Invece puoi usare l'interfaccia Serializable.

Suggerirei di dichiarare l'iterazione su tutte le proprietà nel metodo serialize della classe figlio e archiviarlo in una matrice. Restituire l'array serializzato e serializzare nuovamente tale stringa nel metodo unserialize, riassegnando ogni proprietà in un ciclo.
Se SPLObjectStorage ha proprietà private, si può arrivare a loro in questo modo:

class RoleStorage extends SPLObjectStorage 
     implements Serializable 
{ 
    public function serialize() 
    { 
     return serialize((array) $this); 
    } 
    public function unserialize($string) 
    { 
     $array = unserialize($string); 
     foreach($array as $property => $value) 
     { 
      $property = explode("\0", $property);//private & protected properties 
      $this->{end($property)} = $value; 
     } 
    } 
} 

Per i dettagli sulla explode("\0",$property);, fare riferimento alla manual, o check this question

+0

+1 Sembra che qualcosa venga rimosso da SPLObjectStorage quando si serializza. Buon naso BTW SPLObjectStorage implementa già Serializable. Tuttavia potrebbe ancora essere troppo tardi nella sequenza di spegnimento se la si implementa per conto proprio. Sospetto che il problema si trovi più in profondità nel grafo degli oggetti di quel 'RoleStorage'. – hakre