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;
}
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
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 );
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.
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);
ö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;
}
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'");
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
);
}
$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));
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);
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.
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;
}
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.
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:
;
und prüft, ob der ";
ist:
}
oders:
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
)
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.
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.
Sie müssen den Sortierungstyp in utf8_unicode_ci
ändern und das Problem wird behoben.