fork(5) download
  1. Некоторые функции PHP (strlen, substr, а также обращение к строке как к массиву: $str[0]) не работают с многобайтовыми кодировками (вроде utf-8). В utf-8 1 символ закодирован с помощью от 1 до 6 байтов, а эти функции думают, что 1 буква всегда кодируется одним байтом. По этой причине они ломают символы, в результате получаются битые символы и ничего не работает. Потому вместо них надо использовать mb_ функции например mb_strlen, mb_substr. Вместо доступа к строке как к массиву надо использовать mb_substr.
  2.  
  3. Если тебе интересно, почему эти функции поддерживают только однобайтные кодировки, а не многобайтные, то причина в том, что они очень старые и написаны в то время (лет 40 назад) когда utf-8 и многобайтных кодировок еще не было.
  4.  
  5. Давай разберем пример. Допустим, у нас есть строка из русской буквы «щ» в кодирове utf-8. Попытаемся взять первую букву с помощью неправильной функции:
  6.  
  7.  
  8. // Внимание! это неправильный код, не пиши так!
  9. $s = "щ";
  10. $x = substr($s, 0, 1);
  11.  
  12.  
  13. Буква «щ» кодируется в utf-8 как 2 байта: 209 137 (я взял информацию тут: http://w...content-available-to-author-only...e.de/unicode-utf8-table.pl?start=1024&utf8=dec ). substr отрезает от строки не первую букву, а первый байт. Это значит, что в $x он положит 1 байт с кодом 209. В utf-8 это неверная последовательность, она не соответвует никакому символу (так как после 209 обязательно должно идти второе число). Ideone может вообще отказаться что-то отображать, встретив такой код.
  14.  
  15. То же самое, когда ты обращаешься к строке как к массиву: $s[0]. Эта команда берет не первую букву, а только первый байт строки. Естественно, такая программа не будет работать.
  16.  
  17. Функция strlen считает число байт (не букв) в строке. То есть в данном случае strlen($s) вернет нам 2.
  18.  
  19. Латинница и цифры кодируются в utf-8 одним байтом, с ними это работает, но все равно, не надо использовать эти функции — это слишком ненадежно и легко сделать ошибку.
  20.  
  21. Вывод: используй mb_* функции. Не используй доступ к строке как к массиву. В регулярных выражениях используй флаг u (он говорит что используется utf-8 а не однобайтовая кодировка).
  22.  
  23. Некоторые строковые функции без префикса mb тем не менее корректно работают с utf-8 и их можно использовать. Вот они: strtr (если передавать массив), str_replace, str_repeat, explode, addslashes, trim.
  24.  
  25. Не работают с utf-8: strrev, strlen, substr, strpos, ucfirst, wordwrap, str_pad и большинство других строковых функций, для работы которых нужно считать число символов. Не работает задание ширины в функциях вроде sprintf и printf.
  26.  
  27.  
  28. mbstring.func_overload
  29.  
  30. В неоторых (неграмотных) учебниках ты можешь увидеть совет включить опцию mbstring.func_overload (подробнее про нее: http://p...content-available-to-author-only...p.net/manual/ru/mbstring.overload.php ). Ни в коем случае так не делай, так как это изначально неправильно спроектированная опция. Она не решает проблему, для которой задумывалась (включить в старом приложении использующем функции вроде strlen поддержку utf-8), а лишь создает путаницу. Например, при ее включении strlen заменяется на поддерживающую utf-8 mb_strlen, но ucfirst ни на что не заменяется и не работает.
  31.  
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty