15.06.12

Error at offset x of y bytes – Objekte sicher serialisieren und speichern

Error-at-offset-x-of-y-bytes

Mit der PHP-Funktion serialize lassen sich beliebe Objekte in einen string verwandeln um sie zu speichern. Will man diesen string z.B. in einer MySQL Datenbank speichern kann dies jedoch aufgrund von dessen Aufbau (a:1:{s:25:”yoonic_Test”;O:25:”yoonic_Object”:10:{s:32:”…) der Serialisierung zu Problemen führen.

Eine sichere Alternative ist folgendes:

$strData = serialize($dataObject);
$safeData = base64_encode($strData);

Normalerweise wird das base64-Encoding verwendet um Anhänge von E-Mails zu encoden. Aber für die Serialisierung ist es optimal geeignet, da base64 nur die Zeichen A-Z, a-z, 0-9, +, / und = verwendet um Daten abbildet. So sind Probleme mit Anführungszeichen (in den SQL-Querys) bzw. jegliche Encoding-Probleme von vorherein ausgeschlossen. Jedoch sind base64-Codierte Daten im Schnitt um ca. 30% größer als die originalen Daten. Diesen Nachteil kann man bei Bedarf noch umgehen, indem man die Daten per GZIP komprimiert:

$strData = serialize($dataObject);
$gzipData = gzencode($strData);
$safeData = base64_encode($strData);

Man darf dabei aber nicht vergessen, dass die Komprimierung zu Lasten der CPU und damit der Ausführungszeit geht. Deshalb muss man im Einzelfall abwägen ob man Speichereffizienz oder Performance bevorzugen möchte.

Um seine Daten wieder als Objekt zu bekommen dreht man die Reihenfolge um und benutzt die Decode-Befehle:

$gzipData = base64_decode($safeData);
$strData = gzdecode($gzipData);
$dataObject = unserialize($strData);

Hier nochmal das ganze einsatzbereit, in Funktionen verpackt, Kommentiert und mit Beispiel:

<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');

/*! Serialisiert ein Objekt, so, dass es Problemlos gespeichert werden kann
\param $dataObject Das zu speichernde Objekt
\param $deflate Wenn true werden die Daten mit GZIP komprimiert
\sa unserializeObject()
*/
function serializeObject($dataObject, $deflate = false) {
	$dataObject = serialize($dataObject);
	if($deflate) {
		$dataObject = gzdeflate($dataObject);
	}

	return base64_encode($dataObject);
}

/*! Deserialisiert ein Objekt, das mit serializeObject serialisiert wurde.
\param $dataStr Der zu dekodierende string
\param $deflated Wurden die Daten mit GZIP komprimiert muss $deflated true sein, sonst false.
\sa serializeObject()
*/
function unserializeObject($dataStr, $deflated = false) {
	$dataStr = base64_decode($dataStr);
	if($deflated) {
		$dataStr = gzinflate($dataStr);
	}
	return unserialize($dataStr);
}

//Beispielaufruf:

echo "Komprimiert:\r\n";
$dataObj = array('a','b',3,'d');
var_dump($dataObj);
$strData = serializeObject($dataObj, true);
var_dump($strData);
$obj = unserializeObject($strData, true);
var_dump($obj);

echo "Unkomprimiert:\r\n";
$dataObj = array('a','b',3,'d');
var_dump($dataObj);
$strData = serializeObject($dataObj);
var_dump($strData);
$obj = unserializeObject($strData);
var_dump($obj);
?>

Anmerkung: Wie alle Snippets im yoonic Blog gilt auch für dieses explizit: Public Domain. Jeder kann es nach freiem Belieben verwenden.

Das könnte Sie auch interessieren:


Von: Tags: mysql, php, Web

Sag deine Meinung

Die E-Mail Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.






Suche

Bleibe auf dem Laufenden

Mit dem Newsletter verpasst man nie mehr neue Beiträge und wird trotzdem nicht zugespammt.