使用 UTF-8 编码

| 选择喜欢的代码风格  

PHP 层面的 UTF-8


最基本的字符串操作,像是连结两个字符串或将字符串赋值给变量,并不需要对 UTF-8 做特别的处理。然而大多数字符串的函数,像 strpos()strlen(),确实需要特别的处理。这些函数名中通常包含 mb_*:比如,mb_strpos()mb_strlen()。这些 mb_* 字符串是由 Multibyte String Extension 提供支持的,它专门为操作 Unicode 字符串而特别进行了设计。

在操作 Unicode 字符串时,请你务必使用 mb_* 函数。例如,如果你对一个 UTF-8 字符串使用 substr(),那返回的结果中有很大可能会包含一些乱码。正确的方式是使用 mb_substr()

最难的地方在于每次都要记得使用 mb_* 函数。如果你哪怕只有一次忘记了使用,你的 Unicode 字符串就有在接下来的过程中变成乱码的风险。

不是所有的字符串函数都有一个对应的 mb_* 函数。如果你想要的功能没有对应的 mb_* 函数的话,那只能说你运气不佳了。

你应该在你所有的 PHP 脚本(或全局包含的脚本)的开头使用 mb_internal_encoding() 函数,然后紧接着在会对浏览器进行输出的脚本中使用 mb_http_output()。在每一个脚本当中明确声明字符串的编码可以免去很多日后的烦恼。

另外,许多对字符串进行操作的函数都有一个可选的参数用来指定字符串编码。当可以设定这类参数时,你应该始终明确指定使用 UTF-8。例如,htmlentities() 有一个字符编码的选项,你应该始终将其设为 UTF-8。从 PHP 5.4.0 开始, htmlentities()htmlspecialchars() 的编码都已经被默认设为了 UTF-8。

最后,如果你所编写的是分布式的应用程序并且不能确定 mbstring 扩展一定开启的话,可以考虑使用 patchwork/utf8 Composer 包。它会在 mbstring 可用时自动使用,否则自动切换回非 UTF-8 函数。

数据库层面的 UTF-8


如果你使用 PHP 来操作到 MySQL,有些时候即使你做到了上面的每一点,你的字符串仍可能面临在数据库中以非 UTF-8 的格式进行存储的问题。

为了确保你的字符串从 PHP 到 MySQL都使用 UTF-8,请检查确认你的数据库和数据表都设定为 utf8mb4 字符集和整理,并且确保你的 PDO 连接请求也使用了 utf8mb4 字符集。请看下方的示例代码,这是 非常重要 的。

请注意为了完整的 UTF-8 支持,你必须使用 utf8mb4 而不是 utf8(尤其在开发微信公号和小程序的时候,用户昵称的保存,MySQL一定要用 utfmb4,否则会很坑…如果是SQL SERVER的话,要用 nvarchar!你会在进一步阅读中找到原因。

浏览器层面的 UTF-8


使用 mb_http_output() 函数来确保 PHP 向浏览器输出 UTF-8 格式的字符串。

随后浏览器需要接收 HTTP 应答来指定页面是由 UTF-8 进行编码的。以前这一步是通过在页面 <head> 标签下包含字符集 <meta> 标签实现的,这是一种可行的方式。但更好的做法是在 Content-Type 响应头中进行设置,因为这样做的速度会更快

<?php
// 告诉 PHP 哦我们用 UTF-8 编码,直到脚本执行结束
mb_internal_encoding('UTF-8');
 
// 告诉 PHP that 我们在浏览器以UTF-8编码输出
mb_http_output('UTF-8');
 
// 我们的 UTF-8 字符串
$string = 'Êl síla erin lû e-govaned vîn.';
 
// 使用多字节函数以某种方式转换字符串
// 请注意我们如何在非Ascii字符处剪切字符串以用于演示目的
$string = mb_substr($string, 0, 15);
 
// 连接到数据库以存储转换后的字符串
// 有关详细信息,请参阅本文档中的PDO示例
// 注意数据源名称(DSN)中的`charset = utf8mb4`
$link = new PDO(
    'mysql:host=your-hostname;dbname=your-db;charset=utf8mb4',
    'your-username',
    'your-password',
    array(
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_PERSISTENT => false
    )
);
 
// 将我们转换的字符串存储为UTF-8在我们的数据库中
// 你的数据库和表格是utf8mb4字符集和整理
$handle = $link->prepare('insert into ElvishSentences (Id, Body) values (?, ?)');
$handle->bindValue(1, 1, PDO::PARAM_INT);
$handle->bindValue(2, $string);
$handle->execute();
 
// 检索我们刚存储的字符串以证明它已正确存储
$handle = $link->prepare('select * from ElvishSentences where Id = ?');
$handle->bindValue(1, 1, PDO::PARAM_INT);
$handle->execute();
 
// 存储在数据库中,然后我们HTML中展现出来
$result = $handle->fetchAll(\PDO::FETCH_OBJ);

header('Content-Type: text/html; charset=UTF-8');
?>
<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>UTF-8 test page</title>
    </head>
    <body>
        <?php
        foreach($result as $row){
            print($row->Body);  //正确地将我们转换的UTF-8字符串输出到浏览器
        }
        ?>
    </body>
</html>

PHP UTF-8 扩展阅读:




发表评论