PHP 與 UTF-8

沒有一行式解決方案。當心、注意細節,以及一致性。

PHP 中的 UTF-8 糟透了。原諒個人用詞。php

目前 PHP 在低層次上還不支持 Unicode。有幾種方式能夠確保 UTF-8 字符串可以被正確處理, 但並不容易,須要深刻到 web 應用的全部層面,從 HTML,到 SQL,到 PHP。咱們旨在提供一個簡潔、 實用的概述。html

PHP 層面的 UTF-8

基本的字符串操做,如串接 兩個字符串、將字符串賦給變量,並不須要任何針對 UTF-8 的特殊東西。 然而,多數 字符串函數,如 strpos()strlen,就須要特殊的考慮。 這些函數都有一個對應的 mb_* 函數:例如,mb_strpos()mb_strlen()。 這些對應的函數統稱爲多字節字符串函數。 這些多字節字符串函數是專門爲操做 Unicode 字符串而設計的。java

當你操做 Unicode 字符串時,必須使用 mb_* 函數。 例如,若是你使用 substr() 操做一個 UTF-8 字符串,其結果就極可能包含一些亂碼。 正確的函數應該是對應的多字節函數, mb_substr()mysql

難的是始終記得使用 mb_* 函數。即便你僅一次忘了,你的 Unicode 字符串在接下來的處理中就可能產生亂碼。git

並非全部的字符串函數都有一個對應的 mb_*。若是不存在你想要的那一個,那你就只能自認倒黴了。web

此外,在每一個 PHP 腳本的頂部(或者在全局包含腳本的頂部)你都應使用 mb_internal_encoding 函數,若是你的腳本會輸出到瀏覽器,那麼還得緊跟其後加個mb_http_output() 函數。在每一個腳本中顯式地定義字符串的編碼在之後能爲你減小不少使人頭疼的事情。sql

最後,許多操做字符串的 PHP 函數都有一個可選參數讓你指定字符編碼。 如有該選項, 你應始終顯式地指明 UTF-8 編碼。 例如,htmlentities() 就有一個字符編碼方式選項,在處理這樣的字符串時應始終指定 UTF-8。數據庫

MySQL 層面的 UTF-8

若是你的 PHP 腳本會訪問 MySQL,即便你聽從了前述的注意事項,你的字符串也有可能在數據庫中存儲爲非 UTF-8 字符串。瀏覽器

確保從 PHP 到 MySQL 的字符串爲 UTF-8 編碼的,確保你的數據庫以及數據表均設置爲 utf8mb4 字符集, 而且在你的數據庫中執行任何其餘查詢以前先執行 MySQL 查詢 `set names utf8mb4`。這是相當重要的。 示例請查看鏈接並查詢 MySQL 數據庫一節內容。函數

注意你必須使用 `utf8mb4` 字符集來得到完整的 UTF-8 支持,而不是 `utf8` 字符集!緣由請查看進一步閱讀

瀏覽器層面的 UTF-8

使用 mb_http_output() 函數 來確保你的 PHP 腳本輸出 UTF-8 字符串到瀏覽器。 而且在 HTML 頁面的 <head> 標籤塊中包含 字符集 <meta> 標籤塊

示例

<?php
// Tell PHP that we're using UTF-8 strings until the end of the script
mb_internal_encoding('UTF-8');

// Tell PHP that we'll be outputting UTF-8 to the browser
mb_http_output('UTF-8');

// Our UTF-8 test string
$string = 'Aš galiu valgyti stiklą ir jis manęs nežeidžia';

// Transform the string in some way with a multibyte function
$string = mb_substr($string, 0, 10);

// Connect to a database to store the transformed string
// See the PDO example in this document for more information
// Note the `set names utf8mb4` commmand!
$link = new \PDO(   'mysql:host=your-hostname;dbname=your-db',
                    'your-username',
                    'your-password',
                    array(
                        \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
                        \PDO::ATTR_PERSISTENT => false,
                        \PDO::MYSQL_ATTR_INIT_COMMAND => 'set names utf8mb4'
                    )
                );

// Store our transformed string as UTF-8 in our database
// Assume our DB and tables are in the utf8mb4 character set and collation
$handle = $link->prepare('insert into Sentences (Id, Body) values (?, ?)');
$handle->bindValue(1, 1, PDO::PARAM_INT);
$handle->bindValue(2, $string);
$handle->execute();

// Retrieve the string we just stored to prove it was stored correctly
$handle = $link->prepare('select * from Sentences where Id = ?');
$handle->bindValue(1, 1, PDO::PARAM_INT);
$handle->execute();

// Store the result into an object that we'll output later in our HTML
$result = $handle->fetchAll(\PDO::FETCH_OBJ);
?><!doctype html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>UTF-8 test page</title>
    </head>
    <body>
        <?php
        foreach($result as $row){
            print($row->Body);  // This should correctly output our transformed UTF-8 string to the browser
        }
        ?>
    </body>
</html>

 

進一步閱讀

相關文章
相關標籤/搜索