Quelle est la meilleure façon de déterminer si une chaîne est le résultat de la serialize()
fonction?
Quelle est la meilleure façon de déterminer si une chaîne est le résultat de la serialize()
fonction?
Réponses:
Je dirais, essayez- unserialize
le ;-)
Citant le manuel:
Dans le cas où la chaîne transmise n'est pas non sérialisable, FALSE est renvoyé et E_NOTICE est émis.
Donc, vous devez vérifier si la valeur de retour est false
ou non (avec ===
ou !==
, pour être sûr de ne pas avoir de problème avec 0
ou null
ou quoi que ce soit qui équivaut à false
, je dirais) .
Attention: vous voudrez peut-être / devrez peut-être utiliser l' opérateur @ .
Par exemple :
$str = 'hjkl';
$data = @unserialize($str);
if ($data !== false) {
echo "ok";
} else {
echo "not ok";
}
Vous obtiendrez:
not ok
EDIT: Oh, et comme @Peter l'a dit (grâce à lui!), Vous pourriez avoir des problèmes si vous essayez de désérialiser la représentation d'un booléen false :-(
Donc, vérifier que votre chaîne sérialisée n'est pas égale à " b:0;
" peut également être utile; quelque chose comme ça devrait faire l'affaire, je suppose:
$data = @unserialize($str);
if ($str === 'b:0;' || $data !== false) {
echo "ok";
} else {
echo "not ok";
}
tester ce cas particulier avant d'essayer de désérialiser serait une optimisation - mais probablement pas si utile, si vous n'avez pas souvent une fausse valeur sérialisée.
Je n'ai pas écrit ce code, il vient de WordPress en fait. Je pensais l'inclure pour toute personne intéressée, cela pourrait être exagéré mais cela fonctionne :)
<?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;)
Si la $ string est une false
valeur sérialisée , c'est-à-dire $string = 'b:0;'
que la fonction de SoN9ne retourne false
, c'est faux
donc la fonction serait
/**
* 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.
Nous ne pouvons pas attraper l'erreur E_NOTICE car ce n'est pas une exception levée.
Malgré l'excellente réponse de Pascal MARTIN, j'étais curieux de savoir si vous pouviez aborder cela d'une autre manière, alors je l'ai fait juste comme un exercice mental
<?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 );
}
Et cela fonctionne réellement. La seule mise en garde est qu'il se cassera probablement si vous avez un gestionnaire d'erreurs enregistré à cause du fonctionnement de $ php_errormsg .
$a
et la désérialisation $b
, ce qui n'est pas une conception d'application pratique.
intégrer à une fonction
function isSerialized($value)
{
return preg_match('^([adObis]:|N;)^', $value);
}
a:
(ou b:
etc) est présent quelque part dans $ value, pas au début. Et ^
ici ne signifie pas le début d'une chaîne. C'est totalement trompeur.
Il existe une solution WordPress: (le détail est ici)
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;
}
}
Cela fonctionne bien pour moi
<?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));
}
?>
Je préfère le faire de cette façon:
if (is_array(unserialize($serialized_string))):