2016-08-24 41 views
6

W funkcji mb_detect_encoding znajduje się parametr dla trybu ścisłego.Funkcja PHP mb_detect_encoding tryb ścisły

W pierwszym, najbardziej upvoted komentarza:

<?php 
$str = 'áéóú'; // ISO-8859-1 
mb_detect_encoding($str, 'UTF-8'); // 'UTF-8' 
mb_detect_encoding($str, 'UTF-8', true); // false 

To prawda, tak. Ale czy ktoś może mi wyjaśnić, dlaczego?

+1

Ostatecznie że flaga zostanie przeniesione na [tutaj] (https://github.com/php/php-src/blob/ c72282a13b12b7e572469eba7a7ce593d900a8a2/ext/mbstring/libmbfl/mbfl/mbfilter.C# L718); ale niech mnie diabli, jeśli uda mi się rozgryźć, co robi ... – deceze

+0

FWIW, * jeszcze jeden powód, dla którego nie należy nigdy korzystać z tej funkcji, ponieważ * wykrywanie * kodowania jest zasadniczo niemożliwe. Jednak bardzo interesujące pytanie. – deceze

+0

@deceze Funny: jedyny komentarz na temat 'strict' w całym kodzie źródłowym to'/* set strict flag */' –

Odpowiedz

4

Wszystko w tej odpowiedzi jest oparte na moim odczycie kodu here i here.

Nie napisałem tego, nie zrobiłem tego za pomocą debuggera, to jest tylko moja interpretacja.


Wydaje się, że zamiar był na tryb ścisły, aby sprawdzić, czy ciąg znaków jako całość była ważna do kodowania, natomiast w trybie non-ścisłe pozwoliłoby na sub-sekwencji może być częścią poprawny ciąg. Na przykład, jeśli ciąg zakończył się tym, co powinno być pierwszym bajtem znaku wielobajtowego, nie pasowałoby to w trybie ścisłym, ale nadal kwalifikuje się jako UTF-8 w trybie nie ścisłym.

Jednak wydaje się, że istnieje błąd *, w którym w trybie nie ścisłym sprawdzany jest tylko pierwszy bajt ciągu znaków.

przykład:

Bajt 0xf8 nie może nigdzie UTF-8.Po umieszczeniu na początku ciągu mb_detect_encoding() prawidłowo zwraca dla niego wartość false, niezależnie od tego, który tryb jest używany.

$str = "\xf8foo"; 

var_dump(
    mb_detect_encoding($str, 'UTF-8'),  // bool(false) 
    mb_detect_encoding($str, 'UTF-8', true) // bool(false) 
); 

Ale tak długo, jak długo bajt wiodący może wystąpić w dowolnym miejscu w sekwencji UTF-8, tryb nie ścisły zwraca UTF-8.

$str = "foo\xf8"; 

var_dump(
    mb_detect_encoding($str, 'UTF-8'),  // string(5) "UTF-8" 
    mb_detect_encoding($str, 'UTF-8', true) // bool(false) 
); 

więc w czasie, gdy ISO-8859-1 ciąg 'áéóú' jest nieprawidłowy UTF-8, pierwszy bajt "\xe1" może wystąpić w UTF-8 i mb_detect_encoding() błędnie zwraca łańcuch jako taki.


* Mam otwarty raport dla tego w https://bugs.php.net/bug.php?id=72933

-2

Ponieważ $str nie jest aktualny UTF-8, ale ISO-8859-1. Od kiedy nie jest ścisłym porównania UTF-8 mogą być traktowane tak samo jak ISO-8859-1, ale podczas korzystania z trybu ścisłego tylko rzeczywisty UTF-8 pasuje do UTF-8 porównanie (explained here)

+1

Te specyficzne postacie wyglądają bardzo odmiennie w UTF-8 i 8859. Z pewnością są * nie * takie same i nie mogą być "traktowane tak samo". Dotyczy to tylko pierwszych 128 znaków (ASCII), do których one nie należą. Ten ciąg znaków jest pusty w UTF-8, kropka. – deceze

2

áéóú w ISO-8859-1 koduje jak:

e1 e9 f3 fa 

Jeśli źle interpretujesz to jako UTF-8, otrzymujesz tylko cztery niepoprawne sekwencje bajtów. Rozszerzenie Multi-Byte jest zasadniczo zaprojektowane do ignorowania błędów. Na przykład mb_convert_encoding() zastąpi te sekwencje ciągiem question marks lub czymkolwiek, co ustawisz z mb_substitute_character().

Moja wykształcone przypuszczenie, że ścisłe kodowanie określa, co należy zrobić z nieprawidłowych sekwencji bajtów:

  • false oznacza usunięcie im
  • true znaczy zachować im

Jeśli zignorujesz te nieprawidłowe sekwencje, które w oczywisty sposób odrzucają niezwykle cenne informacje, a otrzymujesz rozsądne wyniki tylko w bardzo ograniczonych okolicznościach, np

$str = chr(81); 
var_dump(mb_detect_encoding($str, ['ISO-8859-1', 'Windows-1252'])); 
var_dump(mb_detect_encoding($str, ['Windows-1252', 'ISO-8859-1'])); 

Podsumowując, mb_detect_encoding() jest w ogóle nie tak dobre, jak ty może rzeczą i to całkowita bzdura z domyślnymi parametrami.

+0

Czy śmiać się, czy płakać, oto jest pytanie. – deceze