2013-07-31 1 views
5

Почему UnexpectedValueException заброшен в session_start()?UnexpectedValueException в session_start() php failing SPLObjectStorage serialization

У меня есть объект, который имеет свойство SPLObjectstorage. Этот объект присваивается сеансу, подобному

Я подозреваю, что внутренняя сессия сериализации сталкивается с проблемой для ее декодирования. Я храню сессию в базе данных, и похоже, что она сериализует objectStorage, но не может ее декодировать.

Sample данные сеанса

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 является простирается от SPLObjectstorage session_decode() на строке выше также возвращает false какие-либо идеи?

Извлечение атрибута roleList делает его сериализацией правильно.

Если я отдельно сделать

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

Он печатает string 'C:11:"RoleStorage":22:{x:i:1;N;,r:3;;m:a:0:{}}' (length=46), а затем терпит неудачу с таким же сообщением во время десериализации. Я не знаю, почему это происходит.

Примечание: при прикреплении объекта к RoleStorage Я использовал сам объект как данные. Значит, он хранится как ссылка. Я не знаю, как (если) делает serialize() обрабатывает внутренне это.

+0

Пожалуйста, также добавьте [hexdump ваших данных сеанса] (http://stackoverflow.com/questions/1057572/how-can-i-get-a-hex-dump-of-a-string-in -PHP). Также в «UnexpectedValueException» есть сообщение. Ваш вопрос пока не содержит этого сообщения, пожалуйста, добавьте его. Он часто содержит важную информацию о проблеме при несериализации. – hakre

ответ

2

Я понятия не имею, почему это происходит

В вашей версии PHP и с ваш конкретный скрипт невозможен для сериализации объекта на основе SPLObjectStorage, если вы не позаботитесь о своей сериализации. Если вы видите эту часть вашей сериализованной строки:

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

Это представляет RoleStorage объекта. Большой C в начале stands for:

C - Объект реализации serializeable Interface

Так что сам объект отвечает здесь о сериализации и unserialization. Обычно вы можете ожидать, что это работает, однако не все программное обеспечение без ошибок.

В вашем случае это похоже на ошибку PHP. Внутренний формат здесь:

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

И проблема в выделенном положении, это требует упорядоченного объекта, а не NULL. И это не запятая с ссылкой (r:13 здесь), но с нулевым (N), чтобы работать.

Так выглядит как зависание, вызванное ссылкой на какой-то более ранний объект (учтите, что этот , ссылающийся на, не совпадает с псевдонимами ссылок/переменных в userland PHP).

Итак, как продолжать?

Пришло время начать изолировать вашу проблему и создать из нее самодостаточный, воспроизводимый пример.Это необходимо для дальнейшего изучения проблемы, как вы ее видите. Это важно по двум причинам:

  1. Если это ошибка в PHP, он должен сообщить, тест регрессии написана и добавлен в PHP Q & A, а затем ошибка исправлена ​​(если еще не фиксированы).
  2. Если вы ищете обходной путь, воспроизведение исходной проблемы необходимо для создания обходного пути быстро и легко.

Я проверил несколько тестов на обход, однако до сих пор я не могу воспроизвести вашу проблему, поэтому я не могу предложить, как обойти эту проблему, поскольку у меня ее нет.

+0

+1 Я попытался найти ресурс в нотации сериализации, но не смог найти его в PHP DOC. Они должны добавить его туда. – varuog

+0

В настоящее время я заменил SPLObjectStorage и абстрактный класс, который использует массив для хранения данных и следует тому же интерфейсу, что и SPLobjectStorage, в качестве временного обходного пути. Как только я изолирую и исправлю проблему, как вы сказали, я просто просто переключу этот базовый абстрактный класс с помощью SPLObjectStorage – varuog

1

Недавно был закрыт вопрос о проблеме, подобной этому. В зависимости от версии php, которую вы используете, вы все равно можете быть затронуты. Исправленная версия - 5.3.15.

Выдержки:

[2012-07-27 16:08 UTC] J точка Хендж-Эрнста на interexa точка де

Проблема заключается в том, что десериализации из ArrayIterator (а также, возможно, ArrayObject или другие классы SPL) не могут разыменовывать объекты ссылок.

Если вы затронуты этой ошибкой, вы можете быть правы, что это связано с разыменованием. Возможно, попробуйте новую версию PHP, чтобы увидеть, все ли это происходит.

+0

Я использую php 5.4.3, что ошибка была указана для «То же поведение с PHP 5.4.5». Наверное, я могу быть затронута. Хотя http://php.net/ChangeLog-5.php changelog не исправляет ошибку. Я не понимаю, почему? Вы знаете, какая версия будет безопасна для ее использования? – varuog

+0

Я пропустил ссылку на 5.4.5. Хороший улов. Похоже, что исправление было совершено всего около 6 недель назад, поэтому, возможно, официального релиза с исправлением не может быть. Возможно, вам придется строить из источника, если вам действительно нужна эта функциональность. http://git.php.net/?p=php-src.git;a=commit;h=04db57066deb73ef9c960a2c5bebad49195bc1bb –

3

Объекты с именем RoleStorage поднимает пару флагов для меня. Часто этот объект содержит ресурс сортов или ссылку на встроенный объект PHP. Ресурсы не могут быть сериализованы, а также не могут быть сериализованы некоторые встроенные типы PHP. В этих случаях рассмотрите возможность применения магии __sleep и __wakeup.
Скажет, у вас есть PDO ссылка где-то в RoleStorage объекте, то эти магические свойства могут выглядеть следующим образом:

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]); 
} 

Но так как вы говорите, в RoleStorage объектах является дочерним SPLObjectStorage, вы бы лучше переопределение реализации SPLObjectStorage «s из the Serializable interface:

Это не представляется возможным для __sleep() возвращает имена частных свойств в родительских классах. Это приведет к ошибке уровня E_NOTICE. Вместо этого вы можете использовать интерфейс Serializable.

Я предлагаю объявить итерацию по всем свойствам метода serialize дочернего класса и сохранить эти данные в массиве. Верните этот сериализованный массив и несериализуйте эту строку обратно в методе unserialize, переназначив каждое свойство в цикле.
Если SPLObjectStorage имеет личные свойства, вы можете получить к ним так:

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; 
     } 
    } 
} 

Для получения дополнительной информации о explode("\0",$property);, обратитесь к manual или check this question

+0

+1 Похоже, что что-то удаляется из SPLObjectStorage при его сериализации. Хороший нос. BTW SPLObjectStorage уже реализует Serializable. Однако, по-прежнему может быть слишком поздно в последовательности выключения, если вы реализуете его самостоятельно. Я подозреваю, что проблема лежит глубже в графе объектов этого 'RoleStorage'. – hakre