139 votes

Vérifier si une chaîne est sérialisée ?

Quelle est la meilleure façon de déterminer si une chaîne de caractères est ou non le résultat de l'exécution de la fonction serialize() fonction ?

https://www.php.net/manual/en/function.serialize

199voto

Pascal MARTIN Points 195780

Je dirais, essayez de unserialize elle ;-)

Citation du manuel :

Dans le cas où la chaîne passée n'est pas unserializeable, FALSE est retourné et E_NOTICE est émis.

Donc, vous devez vérifier si la valeur de retour est false ou non (avec === o !== pour être sûr de ne pas avoir de problème avec 0 o null ou tout ce qui est égal à false je dirais) .

Attention à l'avertissement : vous pourriez avoir envie/besoin d'utiliser l'option @ 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 (merci à lui !), vous pourriez rencontrer des problèmes si vous essayez de désérialiser la représentation d'un booléen faux :-(

Ainsi, vérifier que votre chaîne sérialisée n'est pas égale à " b:0; "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 spécial 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.

20 votes

Mais que se passe-t-il si la valeur non sérialisée est un booléen avec la valeur FALSE ?

1 votes

@Peter : excellente remarque ; j'ai édité ma réponse avec une proposition pour traiter ce cas ; merci !

0 votes

Merci. :) J'ai supposé que ce serait probablement la réponse Il me semble juste qu'il devrait y avoir un moyen de savoir s'il est sérialisé avant de forcer l'analyseur à tenter de le traiter.

60voto

Brandon Wamboldt Points 6248

De WordPress fonctions essentielles :

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

1 votes

J'avais essentiellement besoin d'une regex pour faire une détection de base, j'ai fini par l'utiliser : ^([adObis]:|N;)

6 votes

La version actuelle de WordPress est un peu plus sophistiquée : codex.wordpress.org/Function_Reference/

3 votes

+1 pour l'attribution des crédits. Je ne savais pas que WordPress avait cette fonction intégrée. Merci pour cette idée - je vais maintenant créer une archive des fonctions utiles du noyau de WordPress.

21voto

SoN9ne Points 93

Optimisation de la réponse de Pascal MARTIN

/**
 * Check if a string is serialized
 * @param string $string
 */
public static function is_serial($string) {
    return (@unserialize($string) !== false);
}

13voto

Peter Bailey Points 62125

Malgré l'excellente réponse de Pascal MARTIN, j'étais curieux de savoir si vous pouviez aborder la question d'une autre manière, et j'ai donc fait cet 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 ça marche vraiment. Le seul problème est qu'il y aura probablement une rupture si vous avez un gestionnaire d'erreurs enregistré, en raison de la façon dont le programme $php_errormsg fonctionne .

1 votes

+1 : Celui-ci est amusant, je dois l'admettre - je n'y aurais pas pensé ! Et je ne trouve pas de moyen de le faire échouer, aussi ^^ Beau travail ! Et merci pour le commentaire sur ma réponse : sans lui, je n'aurais probablement pas vu cette réponse.

0 votes

$a = 'bla' ; $b = 'b:0;' ; Essayez de désérialiser $a puis $b avec ceci, les deux échoueront alors que $b ne devrait pas.

0 votes

Pas s'il y a eu un échec juste avant. Parce que $php_errormsg contiendra toujours l'erreur de sérialisation d'avant et une fois que vous désérialisez faux alors il échouera.

11voto

chaos Points 69029
$data = @unserialize($str);
if($data !== false || $str === 'b:0;')
    echo 'ok';
else
    echo "not ok";

Traite correctement le cas de serialize(false) . :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X