Como reparar uma string serializada que foi corrompida por um comprimento de contagem de bytes incorreto?

96

Estou usando o Hotaru CMS com o plugin de upload de imagem, recebo este erro se tento anexar uma imagem a uma postagem, caso contrário, não há erro:

unserialize () [function.unserialize]: Erro no deslocamento

O código ofensivo (o erro aponta para a linha com **):

/**
     * Retrieve submission step data
     *
     * @param $key - empty when setting
     * @return bool
     */
    public function loadSubmitData($h, $key = '')
    {
        // delete everything in this table older than 30 minutes:
        $this->deleteTempData($h->db);

        if (!$key) { return false; }

        $cleanKey = preg_replace('/[^a-z0-9]+/','',$key);
        if (strcmp($key,$cleanKey) != 0) {
            return false;
        } else {
            $sql = "SELECT tempdata_value FROM " . TABLE_TEMPDATA . " WHERE tempdata_key = %s ORDER BY tempdata_updatedts DESC LIMIT 1";
            $submitted_data = $h->db->get_var($h->db->prepare($sql, $key));
            **if ($submitted_data) { return unserialize($submitted_data); } else { return false; }** 
        }
    }

Dados da tabela, observe que o bit final contém as informações da imagem. Não sou um especialista em PHP, então queria saber o que vocês / garotas podem pensar?

tempdata_value:

a:10:{s:16:"submit_editorial";b:0;s:15:"submit_orig_url";s:13:"www.bbc.co.uk";s:12:"submit_title";s:14:"No title found";s:14:"submit_content";s:12:"dnfsdkfjdfdf";s:15:"submit_category";i:2;s:11:"submit_tags";s:3:"bbc";s:9:"submit_id";b:0;s:16:"submit_subscribe";i:0;s:15:"submit_comments";s:4:"open";s:5:"image";s:19:"C:fakepath100.jpg";}

Edit: Acho que encontrei a parte serializar ...

/**
     * Save submission step data
     *
     * @return bool
     */
    public function saveSubmitData($h)
    {
        // delete everything in this table older than 30 minutes:
        $this->deleteTempData($h->db);

        $sid = preg_replace('/[^a-z0-9]+/i', '', session_id());
        $key = md5(microtime() . $sid . rand());
        $sql = "INSERT INTO " . TABLE_TEMPDATA . " (tempdata_key, tempdata_value, tempdata_updateby) VALUES (%s,%s, %d)";
        $h->db->query($h->db->prepare($sql, $key, serialize($h->vars['submitted_data']), $h->currentUser->id));
        return $key;
    }
user576820
fonte
3
Para mim, a solução rápida para isso foi usar base64_encode / decode antes de serializar / desserializar. davidwalsh.name/php-serialize-unserialize-issues
Valentin Despa
1
Eu não sei por que, mas o meu foi resolvido com adicionado @,@unserialize($product->des_txtmopscol);
Bhavin Rana
2
Adicionar @BhavinRana @não é uma solução de erro, é um silenciamento de erro - nada realmente "fica consertado" com essa técnica.
mickmackusa de

Respostas:

219

unserialize() [function.unserialize]: Error at offseteram dívidas invalid serialization datadevido ao comprimento inválido

Conserto rápido

O que você pode fazer é colocar recalculating the lengthos elementos em uma matriz serializada

Seus dados serializados atuais

$data = 'a:10:{s:16:"submit_editorial";b:0;s:15:"submit_orig_url";s:13:"www.bbc.co.uk";s:12:"submit_title";s:14:"No title found";s:14:"submit_content";s:12:"dnfsdkfjdfdf";s:15:"submit_category";i:2;s:11:"submit_tags";s:3:"bbc";s:9:"submit_id";b:0;s:16:"submit_subscribe";i:0;s:15:"submit_comments";s:4:"open";s:5:"image";s:19:"C:fakepath100.jpg";}';

Exemplo sem recálculo

var_dump(unserialize($data));

Resultado

Notice: unserialize() [function.unserialize]: Error at offset 337 of 338 bytes

Recalculando

$data = preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $data);
var_dump(unserialize($data));

Resultado

array
  'submit_editorial' => boolean false
  'submit_orig_url' => string 'www.bbc.co.uk' (length=13)
  'submit_title' => string 'No title found' (length=14)
  'submit_content' => string 'dnfsdkfjdfdf' (length=12)
  'submit_category' => int 2
  'submit_tags' => string 'bbc' (length=3)
  'submit_id' => boolean false
  'submit_subscribe' => int 0
  'submit_comments' => string 'open' (length=4)
  'image' => string 'C:fakepath100.jpg' (length=17)

Recomendação .. eu

Em vez de usar este tipo de solução rápida ... aconselho você a atualizar a questão com

  • Como você está serializando seus dados

  • Como você está salvando ..

==================================== EDITAR 1 ================ ===============

O erro

O erro foi gerado devido ao uso de aspas duplas em "vez de aspas simples, 'por isso C:\fakepath\100.pngfoi convertido paraC:fakepath100.jpg

Para consertar o erro

Você precisa mudar $h->vars['submitted_data']de (Observe o singe ')

Substituir

 $h->vars['submitted_data']['image'] = "C:\fakepath\100.png" ;

Com

 $h->vars['submitted_data']['image'] = 'C:\fakepath\100.png' ;

Filtro Adicional

Você também pode adicionar este filtro simples antes de chamar serializar

function satitize(&$value, $key)
{
    $value = addslashes($value);
}

array_walk($h->vars['submitted_data'], "satitize");

Se você tiver caracteres UTF, também pode executar

 $h->vars['submitted_data'] = array_map("utf8_encode",$h->vars['submitted_data']);

Como detectar o problema em dados serializados futuros

  findSerializeError ( $data1 ) ;

Resultado

Diffrence 9 != 7
    -> ORD number 57 != 55
    -> Line Number = 315
    -> Section Data1  = pen";s:5:"image";s:19:"C:fakepath100.jpg
    -> Section Data2  = pen";s:5:"image";s:17:"C:fakepath100.jpg
                                            ^------- The Error (Element Length)

findSerializeError Função

function findSerializeError($data1) {
    echo "<pre>";
    $data2 = preg_replace ( '!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'",$data1 );
    $max = (strlen ( $data1 ) > strlen ( $data2 )) ? strlen ( $data1 ) : strlen ( $data2 );

    echo $data1 . PHP_EOL;
    echo $data2 . PHP_EOL;

    for($i = 0; $i < $max; $i ++) {

        if (@$data1 {$i} !== @$data2 {$i}) {

            echo "Diffrence ", @$data1 {$i}, " != ", @$data2 {$i}, PHP_EOL;
            echo "\t-> ORD number ", ord ( @$data1 {$i} ), " != ", ord ( @$data2 {$i} ), PHP_EOL;
            echo "\t-> Line Number = $i" . PHP_EOL;

            $start = ($i - 20);
            $start = ($start < 0) ? 0 : $start;
            $length = 40;

            $point = $max - $i;
            if ($point < 20) {
                $rlength = 1;
                $rpoint = - $point;
            } else {
                $rpoint = $length - 20;
                $rlength = 1;
            }

            echo "\t-> Section Data1  = ", substr_replace ( substr ( $data1, $start, $length ), "<b style=\"color:green\">{$data1 {$i}}</b>", $rpoint, $rlength ), PHP_EOL;
            echo "\t-> Section Data2  = ", substr_replace ( substr ( $data2, $start, $length ), "<b style=\"color:red\">{$data2 {$i}}</b>", $rpoint, $rlength ), PHP_EOL;
        }

    }

}

A melhor maneira de salvar no banco de dados

$toDatabse = base64_encode(serialize($data));  // Save to database
$fromDatabase = unserialize(base64_decode($data)); //Getting Save Format 
Baba
fonte
1
Baba, usei sua findSerializeErrorfunção incrível e encontrei muitos erros. Por favor, dê uma olhada no meu tópico
Max Koretskyi
1
usar base64no Artigo antes de adicioná-lo ao banco de dados ... preservaria o caractere nulo
Baba,
1
Essa não é a melhor maneira de salvar no banco de dados. É, a menos que você queira negligenciar completamente o propósito do banco de dados. Como você vai realizar uma pesquisa em um monte de valores criptografados? Sem mencionar o inchaço, ugh. A codificação adequada é a resposta adequada.
Deji
4
Se estiver usando PHP 5.5, consulte a resposta @ r00tAcc3ss! stackoverflow.com/a/21389439/1003020
Vinicius Garcia
5
Se você receber este erro "preg_replace (): O modificador / e não é mais suportado, use preg_replace_callback" no php7 - esta resposta funciona stackoverflow.com/a/21389439/2011434
BenB
81

Não tenho reputação suficiente para comentar, então espero que isso seja visto por pessoas que usam a resposta "correta" acima:

Desde o php 5.5, o modificador / e em preg_replace () se tornou completamente obsoleto e o preg_match acima apresentará um erro. A documentação do php recomenda usar preg_match_callback em seu lugar.

Encontre a seguinte solução como uma alternativa para o preg_match proposto acima.

$fixed_data = preg_replace_callback ( '!s:(\d+):"(.*?)";!', function($match) {      
    return ($match[1] == strlen($match[2])) ? $match[0] : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
},$bad_data );
r00tAcc3ss
fonte
3
Esta parece ser a única resposta na página que realmente coloca o primeiro grupo de captura em bom uso. Embora a programação sensata faça substituições apenas onde a contagem de bytes está realmente errada, esta solução não armazena em cache o strlen()e, portanto, faz chamadas de função redundantes. Pessoalmente, acho que a adição de uma condição inline é muito detalhada, mas esse snippet está fazendo coisas boas por bons motivos.
mickmackusa de
3
Funcionou para mim com a seguinte regex '!s:(\d+):"(.*?)";!s'(com uma terminação 's' para incluir novas linhas também). Obrigado ao comentário de adilbo abaixo.
ArnoHolo
13

Há outro motivo para a unserialize()falha porque você colocou dados serializados incorretamente no banco de dados, consulte a Explicação oficial aqui. Visto que serialize()retorna dados binários e variáveis ​​php não se importam com os métodos de codificação, então colocá-los em TEXT, VARCHAR () causará este erro.

Solução: armazene dados serializados em BLOB em sua tabela.

Ge Rong
fonte
Isso resolveu meu problema no Laravel 5. Eu mudei a definição da coluna de string () para binary ().
WNRosenberg
A pergunta do OP não parece ter um problema de tipo de coluna mysql. Ele está aparentemente corrompido por um cálculo de byte incorreto no imagevalor. Sua resposta não pertence à pergunta específica do OP. Você pode querer mover seu conselho para: stackoverflow.com/q/5544749/2943403
mickmackusa
11

Conserto rápido

Recalcular o comprimento dos elementos na matriz serializada - mas não use (preg_replace) está obsoleto - é melhor usar preg_replace_callback:

Edit: New Version agora não apenas comprimento errado, mas também corrige quebras de linha e conta os caracteres corretos com aczent (graças a mickmackusa )

// New Version
$data = preg_replace_callback('!s:\d+:"(.*?)";!s', function($m) { return "s:" . strlen($m[1]) . ':"'.$m[1].'";'; }, $data);
adilbo
fonte
1
Como essa solução incorreta tem 8 votos positivos? Eu fecho para pensar quantas pessoas teriam, sem querer, copiado e colado este one-liner. [cara triste] Aqui está a prova de duas maneiras em que este snippet falhará: 3v4l.org/Cf6Nh Veja meu padrão refinado e substituição personalizada @ stackoverflow.com/a/55074706/2943403
mickmackusa
1
Minha solução não está mais na outra página porque era uma solução incorreta para a string serializada catastroficamente danificada. Eu adicionei meu snippet a esta página e forneci explicações e demonstrações. stackoverflow.com/a/55566407/2943403
mickmackusa
5

Este erro é causado porque seu conjunto de caracteres está errado.

Definir conjunto de caracteres após abrir a tag:

header('Content-Type: text/html; charset=utf-8');

E defina o conjunto de caracteres utf8 em seu banco de dados:

mysql_query("SET NAMES 'utf8'");
Vai
fonte
Não vejo qualquer indicação na pergunta postada do OP que sugira que a corrupção se deve ao conjunto de caracteres. Sem taxas para defender sua reclamação, mas pelo que posso dizer, alguém atualizou manualmente o imagevalor e não atualizou a contagem de bytes. A menos que informado de outra forma, devo presumir que essa resposta está incorreta para a pergunta do OP.
mickmackusa de
4

Você pode consertar string serializada quebrada usando a seguinte função, com tratamento de caracteres multibyte .

function repairSerializeString($value)
{

    $regex = '/s:([0-9]+):"(.*?)"/';

    return preg_replace_callback(
        $regex, function($match) {
            return "s:".mb_strlen($match[2]).":\"".$match[2]."\""; 
        },
        $value
    );
}
Rajesh Meniya
fonte
O cerne do que esta resposta está recomendando está simplesmente errado e pode danificar strings serializadas perfeitamente válidas. Este snippet não deve ser usado / confiável.
mickmackusa de
@mickmackusa Não estou entendendo. Você pode sugerir a melhor maneira de fazer isso? ou sugira editar nesta resposta ..
Rajesh Meniya
Eu forneci uma solução correta aqui: stackoverflow.com/a/55566407/2943403 e expliquei que mb_strlen()é inadequado porque serialize()armazena a contagem de bytes, não a contagem de caracteres. Editar sua resposta para ser correta apenas criaria conselhos redundantes na página.
mickmackusa de
4

public function unserializeKeySkills ($ string) {

    $output = array();
    $string = trim(preg_replace('/\s\s+/', ' ',$string));
    $string = preg_replace_callback('!s:(\d+):"(.*?)";!', function($m) { return 's:'.strlen($m[2]).':"'.$m[2].'";'; }, utf8_encode( trim(preg_replace('/\s\s+/', ' ',$string)) ));
    try {
        $output =  unserialize($string);
    } catch (\Exception $e) {
        \Log::error("unserialize Data : " .print_r($string,true));
    }
    return $output;
}
Pardeep Goyal
fonte
php unserialize
Pardeep Goyal
Esta solução não é adequada para muitos casos. Ele pressupõe que todos irão querer fazer a mutação dos valores na string serializada para converter 2 ou mais caracteres de espaço em branco em um espaço literal E trim()cada substring correspondente. Esse ponto por si só torna impossível recomendar essa solução. Além disso, ele vai engasgar com caracteres de nova linha e desnecessariamente captura a contagem de bytes pré-existente que será substituída de qualquer maneira. Finalmente, esta é uma "resposta apenas em código" e esses tipos de respostas são de baixo valor, pois fazem pouco para educar / capacitar futuros pesquisadores.
mickmackusa de
4
$badData = 'a:2:{i:0;s:16:"as:45:"d";
Is \n";i:1;s:19:"as:45:"d";
Is \r\n";}';

Você não pode consertar uma string serializada quebrada usando os regexes propostos:

$data = preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.strlen('$2').':\"$2\";'", $badData);
var_dump(@unserialize($data)); // Output: bool(false)

// or

$data = preg_replace_callback(
    '/s:(\d+):"(.*?)";/',
    function($m){
        return 's:' . strlen($m[2]) . ':"' . $m[2] . '";';
    },
    $badData
);
var_dump(@unserialize($data)); // Output: bool(false)

Você pode consertar string serializada quebrada usando o seguinte regex:

$data = preg_replace_callback(
    '/(?<=^|\{|;)s:(\d+):\"(.*?)\";(?=[asbdiO]\:\d|N;|\}|$)/s',
    function($m){
        return 's:' . strlen($m[2]) . ':"' . $m[2] . '";';
    },
    $badData
);

var_dump(@unserialize($data));

Resultado

array(2) {
  [0] =>
  string(17) "as:45:"d";
Is \n"
  [1] =>
  string(19) "as:45:"d";
Is \r\n"
}

ou

array(2) {
  [0] =>
  string(16) "as:45:"d";
Is \n"
  [1] =>
  string(18) "as:45:"d";
Is \r\n"
}
Даниил Путилин
fonte
1
@mickmackusa Obrigado. Corrigido um problema com codificações multibyte.
Даниил Путилин
2

os documentos oficiais diz que ele deve retornar falso e definir E_NOTICE

mas como você obteve o erro, o relatório de erro está configurado para ser acionado por E_NOTICE

aqui está uma correção para permitir que você detecte falso retornado por unserialize

$old_err=error_reporting(); 
error_reporting($old_err & ~E_NOTICE);
$object = unserialize($serialized_data);
error_reporting($old_err);

você pode querer considerar o uso de codificação / decodificação base64

$string=base64_encode(serialize($obj));
unserialize(base64_decode($string));
Muayyad Alsadi
fonte
base64_encodefez o truque para mim. No meu caso, estamos passando serializedados d pela linha de comando e parecia que alguns caracteres estranhos estavam impedindo o funcionamento correto.
quickshift em
base64_encode()não é a solução para a pergunta do OP. A questão / problema do OP está especificamente relacionado ao fato de que (provavelmente devido a uma substituição inadequada de substring no "elemento final da matriz" da string serializada) há uma contagem incorreta de bytes na string serializada. Por favor, poste apenas respostas que lidem diretamente com a pergunta feita.
mickmackusa de
2

A corrupção nesta questão está isolada em uma única substring no final da string serializada com provavelmente foi substituída manualmente por alguém que preguiçosamente queria atualizar o imagenome do arquivo. Esse fato ficará aparente em meu link de demonstração abaixo usando os dados postados do OP - em suma, C:fakepath100.jpgnão tem um comprimento de 19, deveria ser17 .

Uma vez que a corrupção da string serializada é limitada a um número de contagem de byte / caractere incorreto, o seguinte fará um bom trabalho de atualização da string corrompida com o valor de contagem de bytes correto.

A seguinte substituição baseada em regex só será eficaz para corrigir contagens de bytes, nada mais.

Parece que muitas das postagens anteriores estão apenas copiando e colando um padrão regex de outra pessoa. Não há razão para capturar o número de contagem de bytes potencialmente corrompido se ele não for usado na substituição. Além disso, adicionando os modificador de padrão é uma inclusão razoável caso um valor de string contenha novas linhas / retornos de linha.

* Para aqueles que não estão cientes do tratamento de caracteres multibyte com serialização, você não deve usar mb_strlen()no retorno de chamada personalizado porque é a contagem de bytes que é armazenada, não a contagem de caracteres , veja minha saída ...

Código: ( Demo com dados do OP ) ( Demo com dados de amostra arbitrários ) ( Demo com substituição de condição )

$corrupted = <<<STRING
a:4:{i:0;s:3:"three";i:1;s:5:"five";i:2;s:2:"newline1
newline2";i:3;s:6:"garçon";}
STRING;

$repaired = preg_replace_callback(
        '/s:\d+:"(.*?)";/s',
        //  ^^^- matched/consumed but not captured because not used in replacement
        function ($m) {
            return "s:" . strlen($m[1]) . ":\"{$m[1]}\";";
        },
        $corrupted
    );

echo $corrupted , "\n" , $repaired;
echo "\n---\n";
var_export(unserialize($repaired));

Resultado:

a:4:{i:0;s:3:"three";i:1;s:5:"five";i:2;s:2:"newline1
Newline2";i:3;s:6:"garçon";}
a:4:{i:0;s:5:"three";i:1;s:4:"five";i:2;s:17:"newline1
Newline2";i:3;s:7:"garçon";}
---
array (
  0 => 'three',
  1 => 'five',
  2 => 'newline1
Newline2',
  3 => 'garçon',
)

Uma perna abaixo da toca do coelho ... O procedimento acima funciona bem mesmo se as aspas duplas ocorrerem em um valor de string, mas se um valor de string contiver"; procedimento algum outro símbolo assustador, você precisará ir um pouco além e implementar "lookarounds". Meu novo padrão

verifica se o líder s é:

  • o início de toda a string de entrada ou
  • precedido por ;

e verifica se o "; é:

  • no final de toda a string de entrada ou
  • Seguido por } ou
  • seguido por uma string ou declaração inteira s:oui:

Não testei todas as possibilidades; na verdade, não estou familiarizado com todas as possibilidades em uma string serializada porque nunca optei por trabalhar com dados serializados - sempre json em aplicativos modernos. Se houver caracteres adicionais possíveis à esquerda ou à direita, deixe um comentário e estenderei as alternativas.

Snippet estendido: ( Demo )

$corrupted_byte_counts = <<<STRING
a:12:{i:0;s:3:"three";i:1;s:5:"five";i:2;s:2:"newline1
newline2";i:3;s:6:"garçon";i:4;s:111:"double " quote \"escaped";i:5;s:1:"a,comma";i:6;s:9:"a:colon";i:7;s:0:"single 'quote";i:8;s:999:"semi;colon";s:5:"assoc";s:3:"yes";i:9;s:1:"monkey";wrenching doublequote-semicolon";s:3:"s:";s:9:"val s: val";}
STRING;

$repaired = preg_replace_callback(
        '/(?<=^|;)s:\d+:"(.*?)";(?=$|}|[si]:)/s',
        //^^^^^^^^--------------^^^^^^^^^^^^^-- some additional validation
        function ($m) {
            return 's:' . strlen($m[1]) . ":\"{$m[1]}\";";
        },
        $corrupted_byte_counts
    );

echo "corrupted serialized array:\n$corrupted_byte_counts";
echo "\n---\n";
echo "repaired serialized array:\n$repaired";
echo "\n---\n";
print_r(unserialize($repaired));

Resultado:

corrupted serialized array:
a:12:{i:0;s:3:"three";i:1;s:5:"five";i:2;s:2:"newline1
newline2";i:3;s:6:"garçon";i:4;s:111:"double " quote \"escaped";i:5;s:1:"a,comma";i:6;s:9:"a:colon";i:7;s:0:"single 'quote";i:8;s:999:"semi;colon";s:5:"assoc";s:3:"yes";i:9;s:1:"monkey";wrenching doublequote-semicolon";s:3:"s:";s:9:"val s: val";}
---
repaired serialized array:
a:12:{i:0;s:5:"three";i:1;s:4:"five";i:2;s:17:"newline1
newline2";i:3;s:7:"garçon";i:4;s:24:"double " quote \"escaped";i:5;s:7:"a,comma";i:6;s:7:"a:colon";i:7;s:13:"single 'quote";i:8;s:10:"semi;colon";s:5:"assoc";s:3:"yes";i:9;s:39:"monkey";wrenching doublequote-semicolon";s:2:"s:";s:10:"val s: val";}
---
Array
(
    [0] => three
    [1] => five
    [2] => newline1
newline2
    [3] => garçon
    [4] => double " quote \"escaped
    [5] => a,comma
    [6] => a:colon
    [7] => single 'quote
    [8] => semi;colon
    [assoc] => yes
    [9] => monkey";wrenching doublequote-semicolon
    [s:] => val s: val
)
Mickmackusa
fonte
1

Você terá que alterar o tipo de agrupamento para utf8_unicode_cie o problema será corrigido.

Ankit Vishwakarma
fonte
Que caractere específico nos dados de amostra do OP você acredita que será modificado ao alterar o agrupamento para utf8_unicode_ci? Eu tenho minhas dúvidas sobre este.
mickmackusa de
Isso também funcionou para mim (além da resposta de r00tAcc3ss) qualquer palavra de alguém esclarecendo por quê? Como pano de fundo, eu pego dados de uma chamada de API para um aplicativo ResourceSpace, armazeno em um array, serializo e salvo. Os dados serializados estavam tendo problemas para serem salvos, então tive que codificá-los manualmente para UTF-8, estava brincando com agrupamento e conjunto de caracteres no banco de dados e, finalmente, fiquei com agrupamento utf8_general_ci, quando mudei para utf8_unicode_ci, funcionou .
Roberto Becerra
1

No meu caso, eu estava armazenando dados serializados no BLOBcampo do banco de dados MySQL que aparentemente não era grande o suficiente para conter o valor inteiro e o truncou. Obviamente, tal string não poderia ser desserializada.
Uma vez convertido esse campo, MEDIUMBLOBo problema se dissipou. Também pode ser necessário alternar as opções da tabela ROW_FORMATpara DYNAMICou COMPRESSED.

Adam Bubela
fonte
Eu para - embora o meu fosse um TEXTcampo e, como tal, truncado em 65kb.
Antony
Esta pergunta não sofre de truncamento. A questão / problema do OP está especificamente relacionado ao fato de que (provavelmente devido a uma substituição inadequada de substring no "elemento final da matriz" da string serializada) há uma contagem incorreta de bytes na string serializada. Por favor, poste apenas respostas que lidem diretamente com a pergunta feita.
mickmackusa de
1

Depois de tentar algumas coisas nesta página sem sucesso, dei uma olhada no código-fonte da página e observei que todas as citações na string serializada foram substituídas por entidades html. A decodificação dessas entidades ajuda a evitar muitas dores de cabeça:

$myVar = html_entity_decode($myVar);
David
fonte
Esta questão não sofre de entidades codificadas em html na string serializada. A questão / problema do OP está especificamente relacionado ao fato de que (provavelmente devido a uma substituição inadequada de substring no "elemento final da matriz" da string serializada) há uma contagem incorreta de bytes na string serializada. Por favor, poste apenas respostas que lidem diretamente com a pergunta feita.
mickmackusa de
@mickmackusa Esta pergunta tem quase 7 anos e minha resposta ~ 1,5. No entanto, é bom que você se envolva tanto!
David
Eu amo as páginas do SO - jovens e velhos. Procuro pesquisadores que não saibam a diferença entre uma resposta boa e uma resposta não tão boa. Esta página, infelizmente, está cheia de conselhos fora do tópico.
mickmackusa de
Ótimo! Já existe controle de qualidade e votação, mas não tenho motivos para impedi-lo ;-)
David,
Oh não, dê uma olhada. Existem respostas votadas a favor que devem ser votadas negativamente. Muitas pessoas não conseguem diferenciar. Nesta página, a contagem de votos não é absolutamente nenhuma indicação de qualidade / adequação. Não vou perder meu tempo em downvote porque meu downvote não vai prejudicar a contagem. O melhor que posso fazer é deixar comentários explicando o que é bom / ruim / feio.
mickmackusa de
1

Aqui está uma ferramenta online para corrigir uma string serializada corrompida.

Eu gostaria de acrescentar que isso acontece principalmente devido a uma busca e substituição feita no banco de dados e os dados de serialização ( especialmente o key length) não são atualizados de acordo com a substituição e isso causa a "corrupção".

No entanto, a ferramenta acima usa a seguinte lógica para corrigir os dados de serialização ( copiado daqui ).

function error_correction_serialise($string){
    // at first, check if "fixing" is really needed at all. After that, security checkup.
    if ( unserialize($string) !== true &&  preg_match('/^[aOs]:/', $string) ) {
         $string = preg_replace_callback( '/s\:(\d+)\:\"(.*?)\";/s',    function($matches){return 's:'.strlen($matches[2]).':"'.$matches[2].'";'; },   $string );
    }
    return $string;
} 
Mohd Abdul Mujib
fonte
0

Outra razão para este problema pode ser o tipo de coluna da tabela de sessões de "carga útil". Se você tiver muitos dados sobre a sessão, uma coluna de texto não será suficiente. Você precisará do MEDIUMTEXT ou mesmo do LONGTEXT.

GarryOne
fonte
Esta pergunta não sofre de truncamento. A questão / problema do OP está especificamente relacionado ao fato de que (provavelmente devido a uma substituição inadequada de substring no "elemento final da matriz" da string serializada) há uma contagem incorreta de bytes na string serializada. Por favor, poste apenas respostas que lidem diretamente com a pergunta feita.
mickmackusa de