문자열이 직렬화되어 있는지 확인 하시겠습니까?


답변:


191

나는 그것을 시도해보십시오 unserialize;-)

매뉴얼 인용 :

전달 된 문자열을 직렬화 할 수없는 경우 FALSE가 리턴되고 E_NOTICE가 발행됩니다.

그래서, 당신은 반환 값이 있는지 확인해야합니다 false여부 (와 ===!==, 확실하게 어떤 문제가되지 0또는 null하거나 동일 무엇이든 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";
}

직렬화 해제를 시도하기 전에 해당 특수 사례를 테스트하는 것은 최적화 일 것입니다.


20
그러나 직렬화되지 않은 값이 FALSE 값의 부울 인 경우 어떻게해야합니까?
Peter

1
@ 피터 : 우수한 발언; 나는 그 사건을 다루기위한 제안으로 내 대답을 편집했다. 감사 !
Pascal MARTIN

감사. :) 나는 이것이 아마도 답이 될 것이라고 생각했다. 파서가 그것을 처리하도록 실제로 강제하기 전에 그것이 직렬화되었는지 알아내는 방법이 있어야한다고 생각한다.
Dang

1
이 방법이 더 큰 데이터 조각의 성능에 합리적인 영향을 미칩니 까?
pie6k

2
중요 : 원시 사용자 데이터는 공격 경로로 사용될 수 있으므로 절대 직렬화 해제하지 마십시오. OWASP : PHP_Object_Injection
ArtBIT

56

나는이 코드를 쓰지 않았다. 실제로 WordPress에서 온 것입니다. 내가 관심있는 사람을 위해 그것을 포함 할 것이라고 생각했지만 과잉 일 수도 있지만 작동합니다 :)

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

1
나는 기본적으로 기본적인 탐지를하기 위해 정규식이 필요했고, 다음을 사용하여 끝났다.^([adObis]:|N;)
farinspace

5
현재 워드 프레스 버전은 다소 정교하다 : codex.wordpress.org/Function_Reference/…
ChrisV

3
크레딧을주는 +1 워드 프레스에이 내장 기능이 있다는 것을 몰랐습니다. 아이디어 주셔서 감사합니다-이제 WordPress Core에서 유용한 기능의 아카이브를 만듭니다.
Amal Murali

워드 프레스 함수 참조에 대한 최신 URL : developer.wordpress.org/reference/functions/is_serialized
세드릭 Françoys

18

Pascal MARTIN의 응답 최적화

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

16

는 IF $ 문자열 직렬화 된입니다 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);
}

2
이러한 테스트 순서를 바꾸는 것이 더 효율적입니다.
artfulrobot

@ (at 연산자)는 사용하지 않는 것이 좋습니다. 대신 catch catch 블록을 사용하십시오.
Francisco Luz

매뉴얼 php.net/manual/en/function.unserialize.php의 @FranciscoLuz In case the passed string is not unserializeable, FALSE is returned and E_NOTICE is issued. 예외가 아니므로 E_NOTICE 오류를 잡을 수 없습니다.
Hazem Noor

@HazemNoor PHP 7로 테스트했는데 잡히지 않습니다. 또한 PHP 7에는 catch (\ Throwable $ e)가있어 후드에서 잘못되는 모든 것을 잡아냅니다.
Francisco Luz

PHP 7에서 E_Notice를 어떻게 잡았습니까?
user427969

13

Pascal MARTIN의 탁월한 답변에도 불구하고, 다른 방법으로 접근 할 수 있는지 궁금합니다.

<?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 작동 방식으로 인해 등록 된 오류 처리기가 있으면 중단 될 수 있다는 것입니다 .


1
+1 : 이것은 재미 있고, 인정해야합니다 – 그것에 대해 생각하지 않았을 것입니다! 그리고 나는 그것이 실패하게 만드는 방법을 찾지 못한다 ^^ 좋은 일! 그리고 내 대답에 대한 의견에 감사드립니다 : 그것 없이는 아마도이 대답을 보지 못했을 것입니다.
Pascal MARTIN

$ a = 'bla'; $ b = 'b : 0;'; 이것으로 $ a와 $ b를 직렬화 해제하려고 시도하면 $ b는하지 않아야하지만 둘 다 실패합니다.
bardiir

바로 실패가 있었다면 아닙니다. $ php_errormsg는 여전히 이전의 직렬화 오류를 포함하고 false를 직렬화 해제하면 실패합니다.
bardiir

예, deserializing $a과 Deserializing 사이의 오류를 확인하지 않은 경우에만 $b실제 응용 프로그램 디자인이 아닙니다.
Peter Bailey

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

의 경우를 올바르게 처리합니다 serialize(false). :)


3

함수를 구축하다

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

1
이 정규식은 위험이 긍정적 인 경우를 반환 것 a:(또는 b:하지 처음에 $ 값 내부에 존재 곳입니다 등). 그리고 ^여기에서 문자열의 시작을 의미하지는 않습니다. 완전히 오해의 소지가 있습니다.
Denis Chmel

3

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

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

}

5
글쎄, 이것은 많은 JSON 문자열에도 적용됩니다. 따라서 문자열을 직렬화 해제 할 수 있는지 여부를 결정하는 것은 신뢰할 수 없습니다.
고든

사실 일 수도 있지만 대안이 직렬화되어 있거나 평범한 텍스트 인 경우에는 매력처럼 작동합니다.
Björn3

1
@ Björn3 "이 특정한 경우에는 저에게 효과적입니다."는 코딩 할 때 갖는 나쁜 생각입니다. 이와 같이 게 으르거나 앞으로 생각하지 않는 개발자가 많이 있으며 다른 개발자가 코드로 작업하거나 무언가를 변경하려고 할 때 갑자기 더 이상 아무것도 작동하지 않을 때 나중에 악몽을 꾸게됩니다.
BadHorsie

가능하다면 완전한 코드를 작성하는 것이 항상 목표 나 모범 사례는 아닙니다. 시간이 지날 때가 아닙니다. 이것은 프로그래머의 관점에서만 사실입니다. 실제로는 빠르고 더러운 것이 선호되는 많은 환경이 있습니다.
Björn3

1

이것은 나를 위해 잘 작동

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

?>

주어진 문자열이 직렬화 문자열인지 확인합니다. 실제로 해당 문자열의 유효성을 확인하지는 않습니다.
eithed

-2

나는 그렇게하는 것을 선호합니다 :

 if (is_array(unserialize($serialized_string))):

직렬화 된 변수가 왜 배열이어야합니까? 실제로 어떤 유형이든 될 수 있습니다.
Valerio Bozz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.