Когда безопасно использовать функцию PHP strtolower()?

Предполагается, что функция PHP strtolower() преобразует строки в нижний регистр. Но, как сказано в Руководстве по PHP (выделено мной):

Возвращает строку, в которой все буквенные символы преобразованы в нижний регистр.

Обратите внимание, что "алфавитный" определяется текущим языковым стандартом. Это означает, что в локали по умолчанию «C» такие символы, как умляут-A (Ä), не будут преобразованы.

В руководстве ничего не говорится о кодировках, но известно, что strtolower() испортит строки UTF-8, вместо которых вы должны использовать mb_strtolower().

Я ищу решение в тех случаях, когда расширение mbstring недоступно, и хотел узнать, когда безопасно использовать strtolower().

Благодаря указателям, данным мне людьми, комментирующими этот вопрос, кажется, что соответствующая часть исходного кода PHP связана с вызовом функции tolower() в библиотеке ctype.h. В документации библиотеки говорится (выделено мной):

Если аргумент tolower() представляет прописную букву и существует соответствующая строчная буква (как определено информацией о типе символа в категории локали программы LC_CTYPE ), результатом будет соответствующая строчная буква.

Согласно моим тестам, в PHP символы set_locale( LC_CTYPE, 'C' );, такие как Ä (закодированные в ISO-8859-1), остаются нетронутыми. Но в некоторых других локалях функция возвращает ä в нижнем регистре (опять же, в ISO-8859-1). В любом случае, изменение языкового стандарта на тот, который использует набор символов UTF-8, не заставляет PHP strtolower() работать с символом UTF-8 Ä.

Учитывая растущее количество проблем, связанных с I18N, и многоязычные среды, эта информация может быть критически важной. Многие приложения полагаются на strtolower() для простой проверки без учета регистра. Учитывать:

$_POST['username'] = 'Michèlle';
if ( strtolower( $_POST['username'] ) == $database['username'] ) ...

Теперь, в зависимости от кодировки, локалей и, возможно, некоторых других переменных, приведенный выше код будет работать в одних средах, но не в других.

Возникает вопрос: учитывая, что функция PHP strtolower() использует функцию tolower библиотеки ctype.h, которая зависит от "категории локали программы", когда безопасно рассчитывать на эту функцию? Можно ли рассчитывать на такое поведение в следующих случаях?

  1. Строка ASCII
  2. Строка закодирована в ISO-8859-1.
  3. Строка закодирована в какой-то другой кодировке с соответствующим установленным языковым стандартом.

(Изменить: вопрос полностью изменен 26 ноября 2013 г.)


person P_Enrique    schedule 20.11.2013    source источник
comment
PHP имеет открытый исходный код, поэтому найдите его в исходном коде.   -  person Sterling Archer    schedule 20.11.2013
comment
Вот соответствующая часть исходного кода.   -  person Amal Murali    schedule 20.11.2013
comment
@AmalMurali На самом деле работа выполняется здесь: lxr.php. сеть/xref/PHP_TRUNK/ext/standard/string.c#1376   -  person Chris Baker    schedule 20.11.2013
comment
Обратите внимание, что «алфавитный» определяется текущей локалью. Поэтому вы можете взглянуть на эту функцию под названием setlocale. Он сообщает LC_CTYPE для классификации и преобразования символов, например, strtoupper(), поэтому я также думаю, что strtolower. Посмотрите, потому что для локали вы также можете указать кодировку, так что, возможно, это может помочь   -  person Kevin Cittadini    schedule 20.11.2013
comment
@KevinCittadini спасибо, я знаю об этой функции и локалях, но это все еще не отвечает на вопрос о наборах символов и о том, как они здесь используются.   -  person P_Enrique    schedule 20.11.2013
comment
@HeikkiU: Вот почему я разместил комментарий. Во всяком случае, вы сказали, что это действительно внутренняя кодировка, используемая strtolower. Я не знаю ответа, но используя логику, выполняя некоторые тесты с различными конфигурациями setlocale и его кодировкой, возможно, я смогу ответить на ваши вопросы. ИЛИ, конечно, проверьте источник, если хотите.   -  person Kevin Cittadini    schedule 20.11.2013
comment
Я думаю, что тег ‹ctype› здесь уместен, так как ответ на самом деле скрыт где-то там.   -  person P_Enrique    schedule 13.02.2014


Ответы (2)


Функция strtolower() PHP использует функцию tolower() C в своей реализации, которая работает с каждым отдельным байтом (октетом) переданного строкового параметра.

По этой причине set_locale(LC_CTYPE, 'C' ); не повреждает строки в кодировке UTF-8, потому что он не меняет байты> 127. То есть он меняет только регистр символов US-ASCII AZ.

Локаль «C» установлена ​​по умолчанию, и вам не нужно задавать ее явно с помощью setlocale(), только если другие части приложения установили для нее другое значение.

Это также объясняет, почему установка LC_CTYPE в локаль UTF8, например "de_DE.UTF-8", не будет преобразовывать "Ä" в "ä": эта буква кодируется двумя байтами 0xC3 0x84, из которых оба передаются как один символ (октет) в tolower() C. функция - поэтому они неизменны, так как в одном байте UTF-8 для более низкой обработки может обрабатывать только символы ‹ 128, что опять же эффективно только AZ. Что фактически похоже на локаль C.

Таким образом, установка LC_CTYPE в "C" предотвращает нарушение строк UTF-8, используемых с strtolower().

person hakre    schedule 24.01.2016

Он использует функцию c tolower (ссылка: http://www.acm.uiuc.edu/webmonkeys/book/c_guide/2.2.html) из библиотека ctype.h.

Вы можете просмотреть соответствующие разделы источника здесь:

person Chris Baker    schedule 20.11.2013
comment
Из предоставленной вами ссылки: Если символ соответствует соответствующему условию, то он конвертируется. [...] Если символ является символом верхнего регистра (от A до Z), то он преобразуется в нижний регистр (от a до z). Это, по-видимому, не вся правда, поскольку strtolower() БУДЕТ в моей системе конвертировать (ISO-8859 -1 закодировано) от Ä до ä. - person P_Enrique; 20.11.2013
comment
@HeikkiU хм, я смотрю на источник, и php_strtolower действительно прост. Если у вас есть тестовая среда C/C++, попробуйте воспроизвести эти результаты, используя tolower напрямую. Единственное, что я вижу, это то, что strtolower вызывает zend_parse_parameters, но я не вижу там ничего, что указывало бы на какое-то изменение значения, чтобы заставить tolower вести себя иначе, чем обычно. - person Chris Baker; 20.11.2013
comment
У меня нет такой возможности для тестирования. Но в этом должно быть что-то еще, иначе в руководстве было бы просто написано «Преобразует AZ в AZ», не так ли? И, прежде чем вы упомянете об этом, у меня не включена перегрузка mbstring. - person P_Enrique; 20.11.2013
comment
Я отредактировал исходный вопрос, используя часть информации, найденной в вашем ответе. - person P_Enrique; 22.11.2013