W dzisiejszych czasach niezaplątamy sobie głowy kodowaniem tworząc aplikacje w PHP. UTF-8 stał się tak popularny, że nasz zakątek świata nie potrzebuje niczego innego, a jednak…
Gorzej jeśli przyjdzie nam się zderzyć ze światem Windows i z plikami wynikowymi z tego środowiska. Oczywiście, do konwersji WINDOWS-1250 do innego kodowania możemy użyć iconv. Ale co w przypadku gdy nie wiemy skąd pochodzi plik, a w swoim nagłówku nie ma zdefiniowanego kodowania?
Taki przypadek możemy mieć w przypadku plików TXT czy CSV, których zawartość chcemy zaimportować. I wczoraj doznałem szoku. Okazuje się, że PHP nadal w pełni nie obsługuje WINDOWS-1250 – centralno europejskiego kodowania od Microsoftu. Mimo, że w tym celu powstało rozszerzenie MultiByte String wśród wspieranych kodowań brak WINDOWS-1250. W 2009 roku ten błąd był nawet zgłoszony, ale nikt się nim nie zajął.
Przewertowałem sieć i nie znalazłem funkcji, która umożliwiałaby wykrycie kodowania dla pliku, w którym możemy spodziewać się polskich znaczków, tj. UTF-8, WINDOWS-1250, ISO-8859-2. Już chciałem sobie odpuścić, ale to przecież coś bez czego tak naprawdę trudno się obyć.
Kilka minut z konsolą, i proszę – funkcja detectEncoding z obsługą WINDOWS-1250, UTF-8, ISO-8859-2.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
function detectEncoding($string) { $win2utf = array( "\xb9" => "\xc4\x85", "\xa5" => "\xc4\x84", "\xe6" => "\xc4\x87", "\xc6" => "\xc4\x86", "\xea" => "\xc4\x99", "\xca" => "\xc4\x98", "\xb3" => "\xc5\x82", "\xa3" => "\xc5\x81", "\xf3" => "\xc3\xb3", "\xd3" => "\xc3\x93", "\x9c" => "\xc5\x9b", "\x8c" => "\xc5\x9a", "\x9f" => "\xc5\xba", "\xaf" => "\xc5\xbb", "\xbf" => "\xc5\xbc", "\xac" => "\xc5\xb9", "\xf1" => "\xc5\x84", "\xd1" => "\xc5\x83", "\x8f" => "\xc5\xb9"); $countWin = 0; $found = 0; foreach($win2utf as $win => $utf) { $pos = strpos($string, $win); if($pos !== false) { $found++; } if($pos && substr(iconv('WINDOWS-1250', 'UTF-8', $string), $pos+$countWin, 2) == $utf) { $countWin++; } } if($countWin > 0 && $found == $countWin) { return 'WINDOWS-1250'; } if($found) { return 'ISO-8859-2'; } return 'UTF-8'; } |
I teraz możemy już konwertować pliki bez znajomości kodowania:
iconv(detectEncoding($string), 'UTF-8′, $string).