What's the best way to determine whether or not a string is the result of the serialize() function?
What's the best way to determine whether or not a string is the result of the serialize() function?
From WordPress core functions:
<?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;
}
Optimizing Pascal MARTIN's response
/**
* Check if a string is serialized
* @param string $string
*/
public static function is_serial($string) {
return (@unserialize($string) !== false);
}
I would just try to unserialize it. This is how i would solve it
public static function is_serialized($string)
{
try {
unserialize($string);
} catch (\Exception $e) {
return false;
}
return true;
}
Or more like a helper function
function is_serialized($string) {
try {
unserialize($string);
} catch (\Exception $e) {
return false;
}
return true;
}
The mentionned WordPress function does not really detect arrays (a:1:{42} is considered to be serialized) and falsely returns true on escaped strings like a:1:{s:3:\"foo\";s:3:\"bar\";} (although unserialize does not work)
If you use the @unserialize way on the other side WordPress for example adds an ugly margin at the top of the backend when using define('WP_DEBUG', true);
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;
}
see the wordpress function is_serialized
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;
}