检查字符串是否被序列化?

确定字符串是否是 serialize()函数的结果的最佳方法是什么?

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

110253 次浏览

我会说,尝试 unserialize它; -)

引用手册:

如果传递的字符串不是 不可序列化,则返回 FALSE 并且 电子通知书已发出。

因此,必须检查返回值是否为 false

注意: 您可能需要使用 @ 运营商

例如:

$str = 'hjkl';
$data = @unserialize($str);
if ($data !== false) {
echo "ok";
} else {
echo "not ok";
}

会让你:

not ok


编辑: 哦,就像@Peter 说的(多亏了他!)如果您试图反序列化一个布尔错误的表示,您可能会遇到麻烦:-(

因此,检查您的序列化字符串是否等于“ b:0;”也可能是有帮助的; 我认为类似于下面这样的方法应该可以解决这个问题:

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

在尝试反序列化之前测试这个特殊情况将是一种优化——但是如果您不经常有一个错误的序列化值,那么可能没有那么有用。

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

正确处理 serialize(false)的情况。 :)

尽管帕斯卡 · 马丁的回答很棒,我还是很好奇你们是否可以用另一种方式来处理这个问题,所以我这样做只是作为一种心理练习

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

而且真的有用。唯一需要注意的是,如果您有一个已注册的错误处理程序,那么它可能会中断,因为 $php _ errormsg 工作

优化帕斯卡 · 马丁的回答

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

来自 WordPress 核心职能:

<?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;
}
/**
* 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;
}


}

如果 $字符串是序列化的 false值,即 $string = 'b:0;' SoN9ne 的函数返回 false,这是错误的

所以函数应该是

/**
* Check if a string is serialized
*
* @param string $string
*
* @return bool
*/
function is_serialized_string($string)
{
return ($string == 'b:0;' || @unserialize($string) !== false);
}

这对我来说没问题

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


?>

嵌入到函数中

function isSerialized($value)
{
return preg_match('^([adObis]:|N;)^', $value);
}

有 WordPress 解决方案: (详情在这里)

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

查看 wordpress 函数 被连载

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;

}

我会试着解开序列号,这就是我解决问题的方法

public static function is_serialized($string)
{
try {
unserialize($string);
} catch (\Exception $e) {
return false;
}


return true;
}

或者更像是助手函数

function is_serialized($string) {
try {
unserialize($string);
} catch (\Exception $e) {
return false;
}


return true;
}
  • 上面提到的 WordPress 功能并不真正检测数组(a:1:{42}被认为是序列化的) ,并且对转义字符串(如 a:1:{s:3:\"foo\";s:3:\"bar\";})错误地返回 true(尽管 unserialize不工作)

  • 例如,如果你在另一边使用 @unserialize的方式,在使用 define('WP_DEBUG', true);的时候,WordPress 在后端的顶部增加了一个难看的边距

enter image description here

  • 一个既能解决问题又能绕过 stfu 操作员的可行方案是:
function __is_serialized($var)
{
if (!is_string($var) || $var == '') {
return false;
}
set_error_handler(function ($errno, $errstr) {});
$unserialized = unserialize($var);
restore_error_handler();
if ($var !== 'b:0;' && $unserialized === false) {
return false;
}
return true;
}