wake-up-neo.net

unserialize () [function.unserialize]: Fehler beim Offset

Ich verwende Hotaru CMS mit dem Image Upload-Plugin. Ich erhalte diese Fehlermeldung, wenn ich versuche, ein Bild an einen Beitrag anzuhängen. Andernfalls wird kein Fehler angezeigt.

Der fehlerhafte Code (Fehler zeigt auf Zeile mit **):

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

Daten aus der Tabelle, beachten Sie, dass das Endbit die Bildinformationen enthält. Ich bin kein Experte für PHP, also habe ich mich gefragt, was Sie denken könnten.

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: Ich glaube, ich habe das serialisierte Bit gefunden ...

/**
     * 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;
    }
81
user576820

unserialize() [function.unserialize]: Error at offset war wegen ungültiger Länge an invalid serialization data beteiligt

Schnelle Lösung  

Was Sie tun können, ist recalculating the length der Elemente in einem serialisierten Array

Ihre aktuellen serialisierten Daten  

$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";}';

Beispiel ohne Neuberechnung  

var_dump(unserialize($data));

Ausgabe 

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

Neuberechnung  

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

Ausgabe

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)

Empfehlung .. I

Anstatt diese Art von Schnellkorrektur zu verwenden, wird empfohlen, die Frage mit zu aktualisieren 

  • Wie Sie Ihre Daten serialisieren

  • Wie du es rettest ..

================================= BEARBEITEN 1 =============== ====================  

Der Fehler  

Der Fehler wurde aufgrund der Verwendung des doppelten Anführungszeichens " generiert, statt des einfachen Anführungszeichens '. Deshalb wurde C:\fakepath\100.png in C:fakepath100.jpg konvertiert. 

Um den Fehler zu beheben  

Sie müssen $h->vars['submitted_data'] von ändern (Beachten Sie den eindeutigen Code ')

Ersetzen

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

Mit

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

Zusätzlicher Filter  

Sie können diesen einfachen Filter auch hinzufügen, bevor Sie serialize aufrufen 

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

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

Wenn Sie UTF-Zeichen haben, können Sie auch ausführen 

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

So ermitteln Sie das Problem in zukünftigen serialisierten Daten  

  findSerializeError ( $data1 ) ;

Ausgabe

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 Funktion 

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

    }

}

Ein besserer Weg, um in der Datenbank zu speichern  

$toDatabse = base64_encode(serialize($data));  // Save to database
$fromDatabase = unserialize(base64_decode($data)); //Getting Save Format 
200
Baba

Ich habe nicht genug Ruf, um einen Kommentar abzugeben. Ich hoffe, das wird von Leuten gesehen, die die obige "richtige" Antwort verwenden:

Seit PHP 5.5 wurde der/e-Modifizierer in preg_replace () vollständig abgelehnt und der obige preg_match wird fehlerhaft ausgeführt. Die PHP-Dokumentation empfiehlt, stattdessen preg_match_callback zu verwenden.

Die folgende Lösung ist eine Alternative zu dem oben vorgeschlagenen preg_match.

$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 );
53
r00tAcc3ss

Es gibt noch einen anderen Grund, warum unserialize() fehlgeschlagen ist, weil Sie serialisierte Daten nicht ordnungsgemäß in die Datenbank eingegeben haben. Siehe Offizielle Erklärung hier. Da serialize() binäre Daten zurückgibt und PHP-Variablen keine Kodierungsmethoden berücksichtigen, kann der Fehler durch VARCHAR () verursacht werden, wenn Sie sie in TEXT eingeben.

Lösung: Speichern Sie serialisierte Daten in BLOB in Ihrer Tabelle. 

12
Ge Rong

Schnelle Lösung

Neuberechnung der Länge der Elemente in einem serialisierten Array - verwenden Sie jedoch nicht (preg_replace), es ist veraltet.

$data = preg_replace_callback('!s:(\d+):"(.*?)";!', function($m) { return 's:'.mb_strlen($m[2]).':"'.$m[2].'";'; }, $data);
8
adilbo

öffentliche Funktion 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;
}
4
Pardeep Goyal

Dieser Fehler wird verursacht, weil Ihr Zeichensatz falsch ist.

Zeichensatz nach dem Open-Tag setzen: 

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

Und setze den Zeichensatz utf8 in deiner Datenbank: 

mysql_query("SET NAMES 'utf8'");
4
Will

Sie können eine gebrochene serialisierte Zeichenfolge mithilfe der folgenden Funktion mit Multibyte-Zeichen behandeln.

function repairSerializeString($value)
{

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

    return preg_replace_callback(
        $regex, function($match) {
            return "s:".mb_strlen($match[2]).":\"".$match[2]."\""; 
        },
        $value
    );
}
3
Rajesh Meniya
$badData = 'a:2:{i:0;s:16:"as:45:"d";
Is \n";i:1;s:19:"as:45:"d";
Is \r\n";}';

Sie können einen defekten serialisierten String nicht mit den vorgeschlagenen Regex fixieren:

$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:' . mb_strlen($m[2]) . ':"' . $m[2] . '";';
    },
    $badData
);
var_dump(@unserialize($data)); // Output: bool(false)

Sie können einen gebrochenen serialisierten String mit folgendem regulären Ausdruck korrigieren:

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

var_dump(@unserialize($data));

Ausgabe

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

oder

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

die offizielle Dokumentation sagt, dass es false zurückgeben und E_NOTICE setzen soll

da Sie jedoch einen Fehler erhalten haben, wird die Fehlerberichterstattung von E_NOTICE ausgelöst

hier ist ein Fix, mit dem Sie erkennen können, dass von unserialize zurückgegebenes falsches Datum erkannt wird

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

möglicherweise möchten Sie die Verwendung von base64 encode/decode in Betracht ziehen

$string=base64_encode(serialize($obj));
unserialize(base64_decode($string));
2
Muayyad Alsadi

Nachdem ich einige Dinge auf dieser Seite ohne Erfolg ausprobiert hatte, schaute ich in die Seitenquelle und stellte fest, dass alle Anführungszeichen in der serialisierten Zeichenfolge durch HTML-Entities ersetzt wurden .. Die Dekodierung dieser Entities hilft, Kopfschmerzen zu vermeiden:

$myVar = html_entity_decode($myVar);
1
David

In meinem Fall speicherte ich serialisierte Daten im BLOB-Feld von MySQL DB, das anscheinend nicht groß genug war, um den gesamten Wert aufzunehmen und ihn abzuschneiden. Eine solche Zeichenfolge konnte offensichtlich nicht desialisiert werden.
Sobald dieses Feld in MEDIUMBLOB konvertiert wurde, zerstreute sich das Problem . Außerdem kann es erforderlich sein, die Tabellenoptionen ROW_FORMAT in DYNAMIC oder COMPRESSED umzuschalten. 

1
Adam Bubela

Hier ist ein Online-Tool zum Beheben einer beschädigten serialisierten Zeichenfolge.

Ich möchte hinzufügen, dass dies hauptsächlich aufgrund eines Suchens und Ersetzens in der Datenbank und der Serialisierungsdaten ( speziell des key length geschieht. ) wird nicht nach dem Ersetzen aktualisiert und das verursacht die "Korruption".

Das obige Tool verwendet jedoch die folgende Logik, um die Serialisierungsdaten zu korrigieren ( von hier kopiert ).

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

Die Beschädigung in dieser Frage ist auf eine einzelne Teilzeichenfolge am Ende der serialisierten Zeichenfolge beschränkt, die wahrscheinlich manuell durch eine Person ersetzt wurde, die den Dateinamen image träge aktualisieren wollte. Diese Tatsache wird in meinem Demonstrationslink unter Verwendung der vom OP bereitgestellten Daten deutlich - kurz gesagt, C:fakepath100.jpg hat keine Länge von 19, es sollte 17 sein.

Da die Beschädigung der serialisierten Zeichenfolge auf eine falsche Anzahl von Bytes/Zeichen beschränkt ist, kann die beschädigte Zeichenfolge mit der richtigen Anzahl von Bytes aktualisiert werden.

Der folgende reguläre Ausdruck ersetzt nur die Anzahl der Bytes, nicht mehr.

Es sieht so aus, als würden viele der früheren Posts nur ein reguläres Muster von jemand anderem kopieren. Es gibt keinen Grund, die möglicherweise beschädigte Byteanzahl zu erfassen, wenn sie nicht für den Ersatz verwendet wird. Außerdem ist das Hinzufügen des Mustermodifikators s eine sinnvolle Einbeziehung, wenn ein Zeichenfolgenwert Zeilenumbrüche/Zeilenumbrüche enthält.

* Für diejenigen, die die Behandlung von Multibyte-Zeichen mit Serialisierung nicht kennen, dürfen Sie im benutzerdefinierten Rückruf mb_strlen() nicht verwenden, da die Anzahl der gespeicherten Bytes und nicht die Anzahl der Zeichen , siehe meine Ausgabe. .

Code: ( Demo mit OP's Daten ) ( Demo mit beliebigen Beispieldaten ) ( Demo mit Bedingungsersetzung )

$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));

Ausgabe:

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',
)

Ein Bein das Kaninchenloch hinunter ... Das oben Genannte funktioniert auch dann, wenn doppelte Anführungszeichen in einem String-Wert vorkommen, aber wenn ein String-Wert "; oder ein anderes monkeywrenching sbustring enthält, müssen Sie etwas gehen weiter und implementieren "Lookarounds". Mein neues Muster

prüft, ob die führende s ist:

  • der Anfang der gesamten Eingabezeichenfolge oder
  • vorangestellt von ;

und prüft, ob der "; ist:

  • am Ende der gesamten Eingabezeichenfolge oder
  • gefolgt von } oder
  • gefolgt von einer Zeichenfolge oder einer Ganzzahl s: oder i:

Ich habe nicht jede Möglichkeit ausprobiert. Tatsächlich sind mir alle Möglichkeiten einer serialisierten Zeichenfolge relativ unbekannt, da ich mich nie dazu entscheide, mit serialisierten Daten zu arbeiten - in modernen Anwendungen immer json. Wenn es weitere mögliche führende oder nachfolgende Zeichen gibt, hinterlassen Sie einen Kommentar und ich werde die Lookarounds erweitern.

Erweitertes Snippet: ( 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));

Ausgabe:

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
)
0
mickmackusa

Ich hatte das gleiche Problem, als ich die Daten desialisierte. Wenn in einem der Array-Werte ein ",",: oder vorhanden ist, wird die Serialisierung beschädigt. Ich hatte ein: in meinem Array, entfernte es also und es wurde behoben.

Hoffe es hilft jemandem.

0
Sajal

Ein weiterer Grund für dieses Problem kann der Spaltentyp der "Payload" -Sitzungstabelle sein. Wenn Sie große Daten in einer Sitzung haben, würde eine Textspalte nicht ausreichen. Sie benötigen MEDIUMTEXT oder sogar LONGTEXT.

0
GarryOne

Sie müssen den Sortierungstyp in utf8_unicode_ci ändern und das Problem wird behoben.

0