Apa cara terbaik untuk menentukan apakah string adalah hasil dari serialize()
fungsi?
Apa cara terbaik untuk menentukan apakah string adalah hasil dari serialize()
fungsi?
Jawaban:
Saya akan mengatakan, cobalah unserialize
;-)
Mengutip manual:
Jika string yang diteruskan tidak dapat dibatalkan, FALSE dikembalikan dan E_NOTICE dikeluarkan.
Jadi, Anda harus memeriksa apakah nilai pengembaliannya false
atau tidak (dengan ===
atau !==
, untuk memastikan tidak memiliki masalah dengan 0
atau null
atau apa pun yang setara dengan false
, saya katakan) .
Berhati-hatilah dengan pemberitahuan: Anda mungkin ingin / perlu menggunakan operator @ .
Misalnya :
$str = 'hjkl';
$data = @unserialize($str);
if ($data !== false) {
echo "ok";
} else {
echo "not ok";
}
Akan membuat Anda:
not ok
EDIT: Oh, dan seperti yang dikatakan @Peter (terima kasih padanya!), Anda mungkin akan mendapat masalah jika Anda mencoba untuk membatalkan registrasi representasi boolean false :-(
Jadi, memeriksa bahwa string serial Anda tidak sama dengan " b:0;
" mungkin membantu juga; sesuatu seperti ini harus melakukan trik, saya kira:
$data = @unserialize($str);
if ($str === 'b:0;' || $data !== false) {
echo "ok";
} else {
echo "not ok";
}
menguji kasus khusus itu sebelum mencoba unserialize akan menjadi optimasi - tetapi mungkin tidak berguna, jika Anda tidak sering memiliki nilai serial yang salah.
Saya tidak menulis kode ini, sebenarnya dari WordPress. Kupikir aku akan memasukkannya untuk siapa pun yang tertarik, itu mungkin berlebihan tetapi bekerja :)
<?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;)
Jika $ string adalah false
nilai serial , yaitu fungsi $string = 'b:0;'
SoN9ne kembali false
, itu salah
jadi fungsinya akan
/**
* 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.
Kami tidak dapat menangkap kesalahan E_NOTICE karena itu bukan pengecualian.
Terlepas dari jawaban Pascal MARTIN yang luar biasa, saya ingin tahu apakah Anda dapat mendekati ini dengan cara lain, jadi saya melakukan ini hanya sebagai latihan 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 );
}
Dan itu benar-benar berfungsi. Satu-satunya peringatan adalah bahwa kemungkinan akan rusak jika Anda memiliki penangan kesalahan terdaftar karena cara $ php_errormsg bekerja .
$a
dan deserializing $b
, yang bukan desain aplikasi praktis.
membangun fungsi
function isSerialized($value)
{
return preg_match('^([adObis]:|N;)^', $value);
}
a:
(atau b:
dll) ada di suatu tempat di dalam nilai $, bukan di awal. Dan di ^
sini bukan berarti awal dari sebuah string. Benar-benar menyesatkan.
Ada solusi WordPress: (detail ada di sini)
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;
}
}
Ini berfungsi baik untuk saya
<?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));
}
?>
Saya lebih suka melakukannya seperti itu:
if (is_array(unserialize($serialized_string))):