Wie kann am besten festgestellt werden, ob eine Zeichenfolge das Ergebnis der serialize()
Funktion ist oder nicht ?
Wie kann am besten festgestellt werden, ob eine Zeichenfolge das Ergebnis der serialize()
Funktion ist oder nicht ?
Antworten:
Ich würde sagen, versuch unserialize
es ;-)
Zitat des Handbuchs:
Falls die übergebene Zeichenfolge nicht unserialisierbar ist, wird FALSE zurückgegeben und E_NOTICE ausgegeben.
Sie müssen also überprüfen, ob der Rückgabewert ist false
oder nicht (mit ===
oder !==
, um sicherzugehen, dass Sie kein Problem mit 0
oder null
oder etwas haben, das gleich ist false
, würde ich sagen) .
Beachten Sie nur den Hinweis: Möglicherweise möchten / müssen Sie den Operator @ verwenden .
Zum Beispiel :
$str = 'hjkl';
$data = @unserialize($str);
if ($data !== false) {
echo "ok";
} else {
echo "not ok";
}
Kriege dich :
not ok
EDIT: Oh, und wie @Peter sagte (danke an ihn!), Könnten Sie in Schwierigkeiten geraten, wenn Sie versuchen, die Darstellung eines booleschen Falsches zu unserialisieren :-(
Daher kann b:0;
es auch hilfreich sein, zu überprüfen, ob Ihre serialisierte Zeichenfolge nicht gleich " " ist. so etwas sollte den Trick machen, nehme ich an:
$data = @unserialize($str);
if ($str === 'b:0;' || $data !== false) {
echo "ok";
} else {
echo "not ok";
}
Das Testen dieses Sonderfalls vor dem Versuch, unserialisiert zu werden, wäre eine Optimierung - aber wahrscheinlich nicht so nützlich, wenn Sie nicht oft einen falsch serialisierten Wert haben.
Ich habe diesen Code nicht geschrieben, er stammt eigentlich aus WordPress. Ich dachte, ich würde es für alle Interessierten einschließen, es könnte übertrieben sein, aber es funktioniert :)
<?php
function is_serialized( $data ) {
// if it isn't a string, it isn't serialized
if ( !is_string( $data ) )
return false;
$data = trim( $data );
if ( 'N;' == $data )
return true;
if ( !preg_match( '/^([adObis]):/', $data, $badions ) )
return false;
switch ( $badions[1] ) {
case 'a' :
case 'O' :
case 's' :
if ( preg_match( "/^{$badions[1]}:[0-9]+:.*[;}]\$/s", $data ) )
return true;
break;
case 'b' :
case 'i' :
case 'd' :
if ( preg_match( "/^{$badions[1]}:[0-9.E-]+;\$/", $data ) )
return true;
break;
}
return false;
}
^([adObis]:|N;)
Wenn der $ string ein serialisierter false
Wert ist, $string = 'b:0;'
gibt die Funktion von SoN9ne zurückfalse
, ist dies falsch
so wäre die Funktion
/**
* Check if a string is serialized
*
* @param string $string
*
* @return bool
*/
function is_serialized_string($string)
{
return ($string == 'b:0;' || @unserialize($string) !== false);
}
In case the passed string is not unserializeable, FALSE is returned and E_NOTICE is issued.
Wir können den E_NOTICE-Fehler nicht abfangen, da es sich nicht um eine ausgelöste Ausnahme handelt.
Trotz der hervorragenden Antwort von Pascal MARTIN war ich neugierig, ob Sie dies anders angehen könnten, also tat ich dies nur als mentale Übung
<?php
ini_set( 'display_errors', 1 );
ini_set( 'track_errors', 1 );
error_reporting( E_ALL );
$valueToUnserialize = serialize( false );
//$valueToUnserialize = "a"; # uncomment this for another test
$unserialized = @unserialize( $valueToUnserialize );
if ( FALSE === $unserialized && isset( $php_errormsg ) && strpos( $php_errormsg, 'unserialize' ) !== FALSE )
{
echo 'Value could not be unserialized<br>';
echo $valueToUnserialize;
} else {
echo 'Value was unserialized!<br>';
var_dump( $unserialized );
}
Und es funktioniert tatsächlich. Die einzige Einschränkung ist, dass es wahrscheinlich kaputt geht, wenn Sie einen registrierten Fehlerbehandler haben, weil $ php_errormsg funktioniert .
$a
und Deserialisierung keine Fehlerprüfung durchführen $b
, was kein praktisches Anwendungsdesign ist.
in eine Funktion einbauen
function isSerialized($value)
{
return preg_match('^([adObis]:|N;)^', $value);
}
a:
(oder b:
usw.) irgendwo innerhalb von $ value vorhanden ist, nicht am Anfang. Und ^
hier heißt das nicht, dass eine Zeichenfolge beginnt. Es ist total irreführend.
Es gibt WordPress-Lösung: (Detail ist hier)
function is_serialized($data, $strict = true)
{
// if it isn't a string, it isn't serialized.
if (!is_string($data)) {
return false;
}
$data = trim($data);
if ('N;' == $data) {
return true;
}
if (strlen($data) < 4) {
return false;
}
if (':' !== $data[1]) {
return false;
}
if ($strict) {
$lastc = substr($data, -1);
if (';' !== $lastc && '}' !== $lastc) {
return false;
}
} else {
$semicolon = strpos($data, ';');
$brace = strpos($data, '}');
// Either ; or } must exist.
if (false === $semicolon && false === $brace)
return false;
// But neither must be in the first X characters.
if (false !== $semicolon && $semicolon < 3)
return false;
if (false !== $brace && $brace < 4)
return false;
}
$token = $data[0];
switch ($token) {
case 's' :
if ($strict) {
if ('"' !== substr($data, -2, 1)) {
return false;
}
} elseif (false === strpos($data, '"')) {
return false;
}
// or else fall through
case 'a' :
case 'O' :
return (bool)preg_match("/^{$token}:[0-9]+:/s", $data);
case 'b' :
case 'i' :
case 'd' :
$end = $strict ? '$' : '';
return (bool)preg_match("/^{$token}:[0-9.E-]+;$end/", $data);
}
return false;
}
/**
* some people will look down on this little puppy
*/
function isSerialized($s){
if(
stristr($s, '{' ) != false &&
stristr($s, '}' ) != false &&
stristr($s, ';' ) != false &&
stristr($s, ':' ) != false
){
return true;
}else{
return false;
}
}
Das funktioniert gut für mich
<?php
function is_serialized($data){
return (is_string($data) && preg_match("#^((N;)|((a|O|s):[0-9]+:.*[;}])|((b|i|d):[0-9.E-]+;))$#um", $data));
}
?>
Ich mache es lieber so:
if (is_array(unserialize($serialized_string))):