Search code examples
phpcodeignitersessionserializationcodeigniter-2

Unserialize() offset error when using CodeIgniter 2.2 Sessions with Objects


I'm trying to debug some old code from CodeIgniter 2.2. When running some data thru Session, I noticed an unserialize error, Message: unserialize(): Error at offset 160 of 163 bytes. After doing some debugging and research, I found out it's a common backslash issue when unserializing data from Sessions.

The serialized data I'm using has objects of data with backslashes in them, which causes the errors to occur. I'm in need of a replacement that can handle standard class objects as well.

Could someone recommend a quick replacement for codeigniter's Session _serialize() and _unserialize() methods?

public function data_test() {

    $input = array(
        (object)array('name' => 'test2', 'desc' => 'bla bla ob/gyn'),
        (object)array('name' => 'test2', 'desc' => 'bla bla ob\\gyn'),
    );
    var_dump($input);

    $data = $this->_serialize($input);
    var_dump($data);

    $result = $this->_unserialize($data);
    var_dump($result);


}



// --------------------------------------------------------------------

/**
 * Serialize an array
 *
 * This function first converts any slashes found in the array to a temporary
 * marker, so when it gets unserialized the slashes will be preserved
 *
 * @access  private
 * @param   array
 * @return  string
 */
function _serialize($data) {
    if (is_array($data)) {
        foreach ($data as $key => $val) {
            if (is_string($val)) {
                $data[$key] = str_replace('\\', '{{slash}}', $val);
            }
        }
    } else {
        if (is_string($data)) {
            $data = str_replace('\\', '{{slash}}', $data);
        }
    }

    return serialize($data);
}

// --------------------------------------------------------------------

/**
 * Unserialize
 *
 * This function unserializes a data string, then converts any
 * temporary slash markers back to actual slashes
 *
 * @access  private
 * @param   array
 * @return  string
 */
function _unserialize($data) {

    $data = unserialize(strip_slashes($data));

    if (is_array($data)) {
        foreach ($data as $key => $val) {
            if (is_string($val)) {
                $data[$key] = str_replace('{{slash}}', '\\', $val);
            }
        }

        return $data;
    }

    return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data;
}

Solution

  • /**
     * Serialize an array
     *
     * This function serializes the data and then base64_encodes it for 
     * storage with memcached. This avoids the common backslash issue.
     *
     * @access  private
     * @param   array
     * @return  string
     */
    function _serialize($data) {
        return base64_encode(serialize($data));
    }
    
    // --------------------------------------------------------------------
    
    /**
     * Unserialize
     *
     * This function unserializes a data string. I first base64_decodes
     * the data from memcached storage.
     */
    function _unserialize($data) {
        return unserialize(base64_decode($data));
    }