【问题标题】:When is it safe to use the PHP strtolower() function?什么时候可以安全使用 PHP strtolower() 函数?
【发布时间】:2013-11-20 16:25:52
【问题描述】:

PHP strtolower() 函数应该将字符串转换为小写。但是,上面写着in the PHP Manual(强调):

返回字符串,所有字母字符都转换为小写。

请注意,“字母”由当前语言环境决定。这表示 在即默认的“C”语言环境中,诸如变音符号-A (Ä) 之类的字符 不会被转换。

手册在这里没有提及编码,但众所周知strtolower() 会损坏UTF-8 字符串,您应该使用mb_strtolower() 代替。

我正在寻找mbstring 扩展不可用 的解决方案,并想知道何时可以安全使用strtolower()

感谢评论这个问题的人给我的指示,似乎 PHP 源代码的相关部分是对 ctype.h 库中的 tolower() 函数的调用。 library documentation 说(强调):

如果 tolower() 的参数表示一个大写字母,存在 对应的小写字母 (由 program locale category 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() 函数使用 ctype.h 库的 tolower 函数,这取决于“程序语言环境类别”,什么时候可以安全地指望这个函数?在以下情况下是否可以指望该行为?

  1. 字符串是ASCII
  2. 字符串以 ISO-8859-1 编码
  3. 字符串以其他编码和相应的语言环境集进行编码。

编辑:问题于 2013 年 11 月 26 日完全改写。)

【问题讨论】:

  • PHP是开源的,请在源码中找到。
  • @AmalMurali 其实工作在这里完成:lxr.php.net/xref/PHP_TRUNK/ext/standard/string.c#1376
  • "请注意,'字母'由当前语言环境决定"。所以你可能想看看这个名为setlocale 的函数。它报告“用于字符分类和转换的 LC_CTYPE,例如 strtoupper()”,所以我猜 strtolower 也是如此。看一下,因为对于语言环境,您还可以指定编码,所以也许它会有所帮助
  • @KevinCittadini 谢谢,我知道这个函数和语言环境,但这仍然不能回答字符集以及它们在这里如何使用的问题。

标签: php c encoding locale ctype


【解决方案1】:

strtolower() PHP 函数在其实现中使用tolower() C 函数,该函数对传递的字符串参数的每个单字节(八位字节)进行操作。

这就是setlocale(LC_CTYPE, 'C' ); 不会破坏 UTF-8 编码字符串的原因,因为它不会更改大于 127 的字节。也就是说,它只会更改 US-ASCII 字符 A-Z 的大小写。

C”语言环境是默认设置的,您无需使用setlocale() 显式设置它,除非应用程序的其他部分已将其设置为不同的值。

这也解释了为什么将LC_CTYPE 设置为“de_DE.UTF-8”之类的 UTF8 语言环境不会将“Ä”转换为“ä”:该字母使用两个字节 0xC3 0x84 进行编码,这两个字节都被传递作为tolower() C 函数的单个字符(八位字节) - 因此它们没有改变,因为在单个字节上,UTF-8 到较低的处理只能处理

因此将LC_CTYPE 设置为“C”可防止破坏与strtolower() 一起使用的UTF-8 字符串。

【讨论】:

    【解决方案2】:

    它使用来自ctype.h library 的C 函数tolower(参考:http://www.acm.uiuc.edu/webmonkeys/book/c_guide/2.2.html)。

    您可以在此处查看源代码的相关部分:

    【讨论】:

    • 从您提供的链接中:“如果字符匹配适当的条件,则将其转换。[...] 如果字符是大写字符(A 到 Z),则将其转换小写(a 到 z)”这显然不是全部事实,因为 strtolower() 将在我的系统上转换(ISO-8859-1 编码)Ää
    • @HeikkiU 嗯,我在看源码,php_strtolower 真是直截了当。如果您有 C/C++ 测试环境,请尝试直接使用 tolower 重现这些结果。我唯一能看到的另一件事是strtolower 调用zend_parse_parameters,但我没有看到任何表明该值发生某些变化导致tolower 的行为与正常情况不同的东西。
    • 没有测试选项。但肯定还有更多内容,否则手册只会说“将 A-Z 转换为 a-z”,不是吗?而且,在你提到它之前,我没有启用 mbstring 重载。
    • 我已经使用您回答中的一些信息编辑了原始问题。
    • 四分之三的链接(有效地)损坏(ctype.h 一个有效)。第一个链接超时,最后两个重定向到https://heap.space/
    猜你喜欢
    • 1970-01-01
    • 2014-04-13
    • 1970-01-01
    • 2011-02-24
    • 1970-01-01
    • 2020-07-25
    • 1970-01-01
    • 2021-08-31
    • 1970-01-01
    相关资源
    最近更新 更多