2010-03-31 13 views
23

Czy istnieje sposób, aby wykryć, czy ciąg znaków został base64_encoded() w PHP?Wykryj kodowanie base64 w PHP?

Konwertujemy część pamięci masowej z czystego tekstu na bazę 64, a część z nich znajduje się w pliku cookie, który należy zaktualizować. Chciałbym zresetować ich plik cookie, jeśli tekst nie został jeszcze zakodowany, w przeciwnym razie zostaw go w spokoju.

Odpowiedz

24

Przepraszam za opóźnioną odpowiedź na już udzielone pytanie, ale nie sądzę, że base64_decode ($ x, true) jest wystarczająco dobrym rozwiązaniem tego problemu. W rzeczywistości może nie być dobrego rozwiązania, które działa wbrew danym danym. Na przykład mogę umieścić wiele złych wartości w $ x i nie uzyskać fałszywej wartości zwracanej.

var_dump(base64_decode('wtf mate',true)); 
string(5) "���j�" 

var_dump(base64_decode('This is definitely not base64 encoded',true)); 
string(24) "N���^~)��r��[jǺ��ܡם" 

myślę, że oprócz ścisłego sprawdzania wartości zwrot, to trzeba także zrobić walidację po dekodowania. Najbardziej niezawodnym sposobem jest dekodowanie, a następnie sprawdzanie w znanym zestawie możliwych wartości.

Bardziej ogólne rozwiązanie o dokładności mniejszej niż 100% (bliżej dłuższych łańcuchów, niedokładne w przypadku krótkich łańcuchów) jest jeśli sprawdzisz wyjście, aby zobaczyć, czy wiele z nich znajduje się poza normalnym zakresem utf-8 (lub czymkolwiek, co Cię koduje użyj) znaków.

Zobacz ten przykład:

<?php 
$english = array(); 
foreach (str_split('[email protected]#$%^*()_+|}?><": Iñtërnâtiônàlizætiøn') as $char) { 
    echo ord($char) . "\n"; 
    $english[] = ord($char); 
} 
    echo "Max value english = " . max($english) . "\n"; 

$nonsense = array(); 
echo "\n\nbase64:\n"; 
foreach (str_split(base64_decode('Not base64 encoded',true)) as $char) { 
    echo ord($char) . "\n"; 
    $nonsense[] = ord($char); 
} 

    echo "Max nonsense = " . max($nonsense) . "\n"; 

?> 

wyniki:

Max value english = 195 
Max nonsense = 233 

Więc można zrobić coś takiego:

if ($maxDecodedValue > 200) {} //decoded string is Garbage - original string not base64 encoded 

else {} //decoded string is useful - it was base64 encoded 

Powinieneś raczej użyć średnią() z dekodowane wartości zamiast max(), użyłem właśnie max() w tym przykładzie, ponieważ niestety nie ma wbudowanego mean() w PHP. Jaka miara (średnia, maksymalna itd.) W zależności od progu (np. 200) zależy od szacowanego profilu użytkowania.

Podsumowując, jedynym zwycięskim ruchem nie jest granie. Starałbym się unikać rozpoznawania base64 w pierwszej kolejności.

+0

zniechęcanie ... – catbadger

3

miałem zbudować przełącznik base64 w PHP, to co zrobiłem:

function base64Toggle($str) { 
    if (!preg_match('~[^0-9a-zA-Z+/=]~', $str)) { 
     $check = str_split(base64_decode($str)); 
     $x = 0; 
     foreach ($check as $char) if (ord($char) > 126) $x++; 
     if ($x/count($check)*100 < 30) return base64_decode($str); 
    } 
    return base64_encode($str); 
} 

To działa idealnie dla mnie. Oto mój pełny myśli o nim: http://www.albertmartin.de/blog/code.php/19/base64-detection

A tutaj można spróbować: http://www.albertmartin.de/tools

16

miałem ten sam problem, skończyło się z tego rozwiązania:

if (base64_encode(base64_decode($data)) === $data){ 
    echo '$data is valid'; 
} else { 
    echo '$data is NOT valid'; 
} 
+4

Jedyną złą rzeczą jest to, że należy pomyśleć o najpierw ;-) – chrishiestand

+7

Jeśli wykonam $ data = 'iujhklsc', otrzymam ważność, ale tak nie jest; – Mohit

+0

Sprawdzę to .. – Amir

6

Możemy połączyć trzy rzeczy w jedną funkcję, aby sprawdzić, czy dany ciąg jest prawidłową podstawą 64 zakodowaną lub nie.

function validBase64($string) 
{ 
    $decoded = base64_decode($string, true); 

    // Check if there is no invalid character in string 
    if (!preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $string)) return false; 

    // Decode the string in strict mode and send the response 
    if (!base64_decode($string, true)) return false; 

    // Encode and compare it to original one 
    if (base64_encode($decoded) != $string) return false; 

    return true; 
} 
+0

Myślę, że "$ str" powinien w rzeczywistości być "$ string" w drugiej linii. – Wireblue

+0

@Wireblue: Dzięki Mam edytować $ str z $ string –

+0

jeśli nie należy również sprawdzić, czy długość mod wejściowych 4 == 0? – frumbert

0

Zazwyczaj tekst w base64 nie zawiera spacji.

Użyłem tej funkcji, która działała dobrze dla mnie. Testuje, czy liczba spacji w ciągu jest mniejsza niż 1 na 20.

np .: co najmniej 1 miejsce na każde 20 znaków --- (spacje/strlen) < 0.05

function normalizaBase64($data){ 
    $spaces = substr_count ($data ," "); 
    if (($spaces/strlen($data))<0.05) 
    { 
     return base64_decode($data); 
    } 
    return $data; 
} 
1

base64_decode() nie powróci FALSE wejście nie jest ważna base64 zakodowanych danych. Użyj imap_base64() zamiast, zwraca FALSE jeśli $ tekst zawiera znaki spoza alfabetu Base64 imap_base64() Reference

9
function is_base64_encoded($data) 
{ 
    if (preg_match('%^[a-zA-Z0-9/+]*={0,2}$%', $data)) { 
     return TRUE; 
    } else { 
     return FALSE; 
    } 
}; 

is_base64_encoded("iash21iawhdj98UH3"); // true 
is_base64_encoded("#iu3498r"); // false 
is_base64_encoded("asiudfh9w=8uihf"); // false 
is_base64_encoded("a398UIhnj43f/1!+sadfh3w84hduihhjw=="); // true 

http://php.net/manual/en/function.base64-decode.php#81425

+0

Jest to bardzo przydatne, ale twój czwarty przykład to: 'is_base64_encoded (" a398UIhnj43f/1! + Sadfh3w84hduihhjw == "); // true' zwraca FALSE w moich testach. – Dylan

0

Może to nie jest dokładnie to, co już prosiłem. Ale mam nadzieję, że będzie to przydatne dla kogoś.

W moim przypadku rozwiązaniem było zakodowanie wszystkich danych za pomocą json_encode, a następnie base64_encode.

$encoded=base64_encode(json_encode($data)); 

ta wartość może być przechowywana lub używana, co jest potrzebne. Następnie sprawdzić, czy wartość ta nie jest tylko ciąg tekstowy, ale dane zakodowane po prostu użyć

function isData($test_string){ 
    if(base64_decode($test_string,true)&&json_decode(base64_decode($test_string))){ 
     return true; 
    }else{ 
    return false; 
    } 

lub alternatywnie

function isNotData($test_string){ 
    if(base64_decode($test_string,true)&&json_decode(base64_decode($test_string))){ 
     return false; 
    }else{ 
    return true; 
    } 

Dziękujemy wszystkim autorom poprzednich odpowiedzi w tym wątku :)

0

Oto moje rozwiązanie:

if(empty(htmlspecialchars(base64_decode($string, true)))) { return false; }

To zwróci false, jeśli dekodowany $string jest nieprawidłowy, na przykład: „węzeł”, „123”, „”, itp