核心要点
PHP允许使用多字节变量名(例如$a∩b
、$Ʃxy
和$Δx
),mbstring
和其他扩展程序可处理Unicode字符串,utf8_encode()
和utf8_decode()
函数可在UTF-8和ISO-8859-1编码之间转换字符串。然而,人们普遍认为PHP缺乏Unicode支持。本文介绍了缺乏Unicode支持的含义,并演示了如何使用一个为PHP应用程序带来Unicode支持的库——Portable UTF-8。
PHP中的Unicode支持
PHP缺乏Unicode/多字节支持意味着标准字符串处理函数将字符串视为单字节字符序列。事实上,PHP官方手册将PHP中的字符串定义为“一系列字符,其中一个字符与一个字节相同”。PHP仅支持8位字符,而Unicode(以及许多其他字符集)可能需要多个字节来表示一个字符。PHP的这一限制几乎影响字符串操作的各个方面,包括(但不限于)子字符串提取、确定字符串长度、字符串分割、混排等。解决这个问题的努力始于2005年初,但在2010年,由于多种原因,将原生Unicode支持引入PHP的工作被停止并搁置。由于PHP中的原生Unicode支持可能需要数年时间才能实现(如果真的会实现的话),开发人员必须依赖可用的mbstring
和iconv
等扩展来填补这一空白,但这些扩展只提供有限的Unicode支持。这些库并非以Unicode为中心,也能够在非Unicode编码之间进行转换。它们为简化Unicode字符串处理做出了积极贡献。但是,上述扩展也有一些缺点。它们仅提供有限的Unicode字符串处理功能,并且没有一个默认启用。服务器管理员必须显式启用任何一个或所有扩展才能通过PHP应用程序访问它们。共享主机提供商通常会通过安装一两个扩展来使情况变得更糟,这使得开发人员难以依靠始终可用的API来满足其Unicode需求。尽管如此,好消息是PHP可以输出Unicode文本。这是因为PHP并不真正关心我们是否正在发送以ASCII编码的英文文本或属于其字符以多个字节编码的语言的其他文本。了解这一点后,PHP开发人员现在只需要一个提供舒适的基于Unicode的字符串操作的API。
Portable UTF-8
最近的解决方案是创建用PHP编写的用户空间库。即使服务器/语言级别缺少支持,这些库也可以轻松地与应用程序捆绑在一起,以确保Unicode支持的存在。许多开源应用程序已经包含了自己的此类库,还有更多应用程序使用免费提供的第三方库;Portable UTF-8就是这样一个库。Portable UTF-8是一个免费的轻量级库,构建在mbstring
和iconv
之上。它扩展了这两个扩展的功能,提供了大约60个基于Unicode的字符串操作、测试和验证函数;它为几乎所有PHP的常用字符串处理函数提供了UTF-8感知的对应函数。顾名思义,Portable UTF-8使用UTF-8作为其主要字符编码方案。该库出于速度原因而使用可用的扩展(mbstring
和iconv
),并弥合了直接使用它们时的一些不一致之处,但如果服务器上没有这些扩展,则会回退到用纯PHP编写的UTF-8例程。Portable-UT8完全可移植,可与任何PHP 4.2或更高版本的安装一起使用。
使用Portable UTF-8进行字符串处理
具有较差Unicode支持的文本编辑器在读取文本时可能会损坏文本,从这样的编辑器复制并粘贴到Web表单中的文本可能是应用程序无效UTF-8的来源。在处理用户提交的输入时,务必确保输入完全符合应用程序的预期。要检测文本是否为有效的UTF-8,可以使用库的is_utf8()
函数。
<code class="language-php">if (is_utf8($_POST['title'])) { // 执行某些操作... }</code>
从无效字节中恢复字符是不可能的,因此去除无法识别为有效UTF-8字符的字节可能是您的唯一选择。可以使用utf8_clean()
函数去除无效字节。
<code class="language-php">$title = utf8_clean($_POST['title']);</code>
每个Unicode字符都可以编码为相应的HTML实体,您可能希望以这种方式编码文本以帮助防止XSS攻击,然后再将其输出到浏览器。
<code class="language-php">echo utf8_html_encode($title);</code>
通常会在字符串的开头和结尾修剪空格。Unicode列出了大约20个空格字符,还有一些基于ASCII的控制字符也应被视为需要修剪的对象。
<code class="language-php">$title = utf8_trim($title);</code>
另一方面,字符串中间可能存在此类空格的重复项,应将其删除。以下显示了如何将utf8_remove_duplicates()
和utf8_ws()
组合使用:
<code class="language-php">$title = utf8_remove_duplicates($title, utf8_ws());</code>
用于创建URL片段以实现SEO目的的传统解决方案使用音译并从片段中去除所有非ASCII字符。这使得URL的价值低于其本来的价值。虽然URL可以支持UTF-8编码的字符,但无需进行此类去除或音译,我们可以创建包含任何语言字符的丰富片段:
<code class="language-php">$slug = utf8_url_slug($title, 30); // 字符长度30</code>
从输入验证开始到将数据保存到某个数据库,支持Unicode的应用程序关注的是字符和字符长度,而不是字节和字节长度。这种关注点的转变需要一个理解这种差异的新接口。通常需要对输入字符长度进行限制,因此,如果输入超过60个字符的长度,我们将创建一个子字符串。
<code class="language-php">if (utf8_strlen($title) > 60) { $title = utf8_substr($title, 0, 60); }</code>
或者:
<code class="language-php">if (!utf8_fits_inside($title , 60)) { $title = utf8_substr($title, 0 ,60); }</code>
使用Portable-UT8库有三种不同的方法可以访问单个字符。我们可以使用utf8_access()
来访问单个字符。
<code class="language-php">echo '第六个字符是:' . utf8_access($string, 5);</code>
utf8_chr_map()
允许使用回调函数迭代地访问单个字符。
<code class="language-php">utf8_chr_map('some_callback', $string);</code>
我们可以使用utf8_split()
将字符串拆分为字符数组,并将数组元素作为单个字符进行处理。
<code class="language-php">array_map('some_callback', utf8_split($string));</code>
处理Unicode可能还需要我们查找字符串中的最小/最大代码点、分割字符串、处理字节顺序标记、字符串大小写转换、随机化/混排、替换等。所有这些都受Portable-UT8支持。
结论
PHP 6的开发已被停止,导致长期需要的原生Unicode支持被推迟,这对于开发多语言应用程序至关重要。因此,在此期间,服务器端扩展和用户空间库(如Portable UTF-8)在帮助开发人员创建更好的标准化Web,以满足本地需求方面发挥着重要作用。
(由于篇幅限制,此处省略了FAQs部分)
以上是使用便携式UTF-8将Unicode带到PHP的详细内容。更多信息请关注PHP中文网其他相关文章!