PHP strtolower()
函数应该将字符串转换为小写。但是,它在PHP手册中说(增加了重点):
返回所有字母字符都转换为小写的字符串。
请注意,"字母"由当前区域设置决定。这意味着在默认的"C"语言环境中,元音变音符-A(É)等字符将不会转换。
手册中没有提及编码,但众所周知,strtolower()
会破坏UTF-8字符串,而应该使用mb_strtolower()
。
我正在寻找mbstring
扩展不可用的情况下的解决方案,我想知道什么时候使用strtolower()
是安全的。
多亏了评论这个问题的人给我的指针,PHP源代码的相关部分似乎是对ctype.h
库中tolower()
函数的调用。图书馆文件上写着(重点加上):
如果tolower()的参数表示一个大写字母,并且存在对应的小写字母(由程序语言环境类别LC_CTYPE),结果应为小写字母。
根据我的测试,在带有set_locale( LC_CTYPE, 'C' );
字符的PHP中,比如Ä
(在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()
函数使用ctype.h
库的tolower
函数,这取决于"程序区域设置类别",那么什么时候可以安全地使用此函数?在以下情况下,这种行为可以指望吗?
- 字符串为ASCII
- 该字符串在ISO-8859-1中编码
- 该字符串以其他一些编码方式进行编码,并带有相应的区域设置
(编辑:问题于2013年11月26日完全改写。)
strtolower()
PHP函数在其实现中确实使用了tolower()
C函数,该函数对传递的字符串参数的每个单字节(八位字节)进行操作。
这就是setlocale(LC_CTYPE, 'C' );
不会损坏UTF-8编码字符串的原因,因为它不会更改字节>127.也就是说,它只改变了US-ASCII字符A-Z的大小写。
";CCD_ 20";locale是默认设置的,您不需要用setlocale()
显式设置它,只有当应用程序的其他部分将它设置为不同的值时。
这也解释了为什么将CCD_ 22设置为UTF8语言环境;CCD_ 23";不会转换";CCD_ 24";至";ä
〃:该字母由两个字节0xC3 0x84编码,其中两个字节都作为单个字符(八位位组)传递给tolower()
C函数,因此它们没有变化,因为在单个字节上,UTF-8到更低的处理只能处理字符<128,其同样有效地仅为A-Z。这实际上就像C语言环境。
因此将CCD_ 27设置为"0";CCD_ 28";防止与strtolower()
一起使用时中断UTF-8字符串。
它使用C函数tolower
(参考:http://www.acm.uiuc.edu/webmonkeys/book/c_guide/2.2.html)来自ctype.h库。
您可以在此处查看来源的相关部分:
- 其中CCD_ 31被定义为:http://lxr.php.net/xref/PHP_TRUNK/ext/standard/string.c#1393
- 其中CCD_ 32在CCD_http://lxr.php.net/xref/PHP_TRUNK/ext/standard/string.c#1376