Dizenin serileştirilip serileştirilmediğini kontrol ettiniz mi?


Yanıtlar:


191

Ben denemeliyim unserialize;-)

Kılavuzdan alıntı:

Geçirilen dizenin seri hale getirilememesi durumunda, FALSE döndürülür ve E_NOTICE verilir.

Yani, dönüş değeri olup olmadığını kontrol etmek zorunda falseolmadığını (ile ===veya !==, emin olmak için herhangi bir sorunu olmadığı 0veya nullveya eşittir şey falsediyebilirim) .

Sadece uyarılara dikkat edin: @ işlecini kullanmak isteyebilir / kullanmanız gerekebilir .

Örneğin :

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

Seni alacak :

not ok


DÜZENLEME: Oh, ve @Peter'in dediği gibi (ona teşekkürler!), Bir boole yanlışının temsilini diziselleştirmeye çalışıyorsanız sorun yaşayabilirsiniz :-(

Bu nedenle, serileştirilmiş dizenizin " b:0;" ile eşit olmadığını kontrol etmek de yardımcı olabilir; böyle bir şey hile yapmalı, sanırım:

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

serileştirmeye çalışmadan önce bu özel durumun test edilmesi bir optimizasyon olacaktır - ancak genellikle yanlış bir serileştirilmiş değeriniz yoksa bu yararlı olmaz.


20
Peki ya serileştirilmemiş değer YANLIŞ değerine sahip bir boole ise?
Peter

1
@Peter: mükemmel not; Cevabımı, bu dava ile başa çıkma önerisiyle düzenledim; Teşekkürler !
Pascal MARTIN

Teşekkürler. :) Bunun muhtemelen cevap olacağını sanıyordum .. Bana göre, aslında ayrıştırıcıyı işlemeyi denemeye zorlamadan önce seri hale getirilip getirilmediğini öğrenmenin bir yolu olmalı.
Dang

1
Bu yöntemin daha büyük veri parçalarıyla performans üzerinde makul bir etkisi var mı?
pie6k

2
ÖNEMLİ: Saldırı vektörü olarak kullanılabileceğinden hiçbir zaman ham kullanıcı verilerinin serisini kaldırmayın. OWASP: PHP_Object_Injection
ArtBIT

56

Bu kodu yazmadım, aslında WordPress'ten. İlgilenen herkes için dahil edeceğimi düşündüm, aşırı olabilir ama işe yarıyor :)

<?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
Temelde temel bir tespit yapmak için bir regex gerekli, ben kullanarak sona erdi:^([adObis]:|N;)
farinspace

5
Mevcut WordPress sürümü biraz daha karmaşık: codex.wordpress.org/Function_Reference/…
ChrisV

3
Kredi vermek için +1. WordPress'in bu yerleşik olduğunu bilmiyordum. Fikir için teşekkürler - Şimdi devam edeceğim ve WordPress Core'dan kullanışlı işlevlerin bir arşivini oluşturacağım.
Amal Murali

En son wordpress fonksiyon referansı URL'si: developer.wordpress.org/reference/functions/is_serialized
Cédric Françoys

18

Pascal MARTIN'in yanıtını optimize etme

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

16

Eğer $ dizesi bir seri hale falsedeğeri, yani $string = 'b:0;' SoN9ne 'ın işlevini verirfalse ,' s yanlış

böylece fonksiyon

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

2
Bu testlerin sırasını değiştirmek daha verimli olacaktır.
artfulrobot

@ (Operatörde) önerilmez. Bunun yerine try catch bloğunu kullanın.
Francisco Luz

@ Php.net/manual/en/function.unserialize.php kılavuzundan @FranciscoLuz In case the passed string is not unserializeable, FALSE is returned and E_NOTICE is issued. E_NOTICE hatasını atılmış bir istisna olmadığı için yakalayamıyoruz.
Hazem Noor

@HazemNoor PHP 7 ile test ettim ve yakalandı. Ayrıca, PHP 7'de, başlık altında yanlış giden her şeyi yakalayan catch (\ Throwable $ e) vardır.
Francisco Luz

@FranciscoLuz PHP 7'de E_Notice'i nasıl yakaladınız?
user427969

13

Pascal MARTIN'in mükemmel cevabına rağmen, buna başka bir şekilde yaklaşıp yaklaşamayacağınızı merak ettim, bu yüzden bunu sadece zihinsel bir egzersiz olarak yaptım

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

Ve aslında işe yarıyor. Tek uyarı $ php_errormsg nasıl çalışır nedeniyle kayıtlı bir hata işleyicisi varsa büyük olasılıkla kırmak olacaktır .


1
+1: Bu eğlenceli, itiraf etmeliyim - bunu düşünmezdim! Ve ben de başarısız yapmanın bir yolunu bulamıyorum ^^ Güzel iş! Ve cevabım hakkındaki yorum için teşekkürler: onsuz, muhtemelen bu cevabı göremezdim.
Pascal MARTIN

$ a = 'bla'; $ b = 'b: 0;'; $ A sonra $ b öğesinin serisini kaldırmayı deneyin, $ b olmamalı, her ikisi de başarısız olacaktır.
bardiir

Daha önce başarısız olsaydı değil. $ Php_errormsg hala önceki serileştirme hatasını içereceğinden ve bir kez yanlış serisini kaldırdığınızda başarısız olur.
bardiir

Evet, ancak sadece uygulama uygulama tasarımı değil, seri kaldırma $ave seri kaldırma arasındaki hataları kontrol etmezseniz $b.
Peter Bailey

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

Durumunu doğru şekilde işler serialize(false). :)


3

bir fonksiyon oluşturmak

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

1
Bu normal ifade tehlikelidir, başlangıçta değil, $ değerinin içinde a:(veya b:vb.) Bir yerde bulunduğunda olumlu sonuç verir . Ve ^burada bir ipin başlangıcı anlamına gelmez. Tamamen yanıltıcı.
Denis Chmel

3

WordPress çözümü var: (detay burada)

    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
Peki, bu birçok JSON dizesi için de geçerli olurdu, değil mi? Bu nedenle, dizenin un / serileştirilip birleştirilemeyeceğini belirlemek güvenilir değildir.
Gordon

Doğru olabilir, ancak alternatif seri hale getirilmişse veya sadece düz metinse, benim için olduğu gibi, bir cazibe gibi çalışır.
Björn3

1
@ Björn3 "Bu özel durumda benim için çalışıyor" kodlamada sahip olmak gerçekten kötü bir zihniyet. Bu şekilde tembel ya da ileri görüşlü olmayan birçok geliştirici var ve diğer geliştiriciler kodlarıyla çalışmak ya da bir şeyi değiştirmeye çalışmak zorunda kaldığında daha sonra bir kabus yaratıyor ve aniden hiçbir şey artık düzgün çalışmıyor.
BadHorsie

Tamamen sağlam bir kod yapmak (eğer mümkünse) her zaman amaç veya en iyi uygulama değildir. Bir zaman geldiğinde değil. Bu sadece programcıların bakış açısından doğrudur. Gerçek hayatta, hızlı ve kirli tercih edilen yolun olduğu birçok olay vardır.
Björn3

1

Bu benim için iyi çalışıyor

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

?>

Bu dizenin seri hale getirilmiş dizge olup olmadığını kontrol ettiğini lütfen unutmayın - bu dizenin geçerliliğini kontrol etmez.
42'de eithed

-2

Bu şekilde yapmayı tercih ederim:

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

Serileştirilmiş değişken neden bir dizi olmalıdır? Gerçekten ne tür olursa olsun olabilir.
Valerio Bozz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.