php get meta tags




UTF-8一路通過 (10)

PHP中的Unicode支持仍然是一個巨大的混亂。 雖然它能夠將ISO8859字符串(它在內部使用)轉換為utf8,但它本身沒有使用unicode字符串的能力,這意味著所有的字符串處理函數都會破壞和破壞字符串。 所以你必須使用單獨的庫來獲得適當的utf8支持,或者自己重寫所有的字符串處理函數。

簡單的部分就是在HTTP頭文件和數據庫中指定charset等,但如果您的PHP代碼不輸出有效的UTF8,那麼這些都不重要。 這是一個很難的部分,而PHP在這方面幾乎沒有任何幫助。 (我認為PHP6應該可以解決最糟糕的問題,但這還有一段時間了)

我正在設置一個新的服務器,並且希望在我的Web應用程序中完全支持UTF-8。 過去我在現有的服務器上嘗試過,並且似乎最終不得不回退到ISO-8859-1。

我在哪裡需要設置編碼/字符集? 我知道我需要配置Apache,MySQL和PHP來做到這一點 - 是否有一些我可以遵循的標準清單,或者可能需要排除發生不匹配的問題?

這是一個新的Linux服務器,運行MySQL 5,PHP 5和Apache 2。


數據存儲

  • 在數據庫中的所有表和文本列上指定utf8mb4字符集。 這使MySQL實際存儲和檢索以UTF-8本地編碼的值。 請注意,如果指定了utf8mb4_*排序規則(沒有任何明確的字符集),MySQL將隱式使用utf8mb4編碼。

  • 在舊版本的MySQL(<5.5.3)中,不幸的是你不得不僅僅使用utf8 ,它只支持一部分Unicode字符。 我希望我在開玩笑。

數據訪問

  • 在您的應用程序代碼(例如PHP)中,無論您使用utf8mb4數據庫訪問方法,都需要將連接字符集設置為utf8mb4 。 這樣,MySQL在將數據傳遞到應用程序時不會從其本機UTF-8進行轉換,反之亦然。

  • 一些驅動程序提供了自己的配置連接字符集的機制,它們都會更新自己的內部狀態並通知MySQL將在連接上使用的編碼 - 這通常是首選方法。 在PHP中:

    • 如果您使用PDO抽象層,則可以在DSN指定charset

      $dbh = new PDO('mysql:charset=utf8mb4');
      
    • 如果你使用mysqli ,你可以調用set_charset()

      $mysqli->set_charset('utf8mb4');       // object oriented style
      mysqli_set_charset($link, 'utf8mb4');  // procedural style
      
    • 如果你遇到了普通的mysql但碰巧運行的是PHP≥5.2.3,則可以調用mysql_set_charset

  • 如果驅動程序沒有提供自己的設置連接字符集的機制,那麼您可能必鬚髮出一個查詢來告訴MySQL您的應用程序期望連接上的數據是如何編碼的: SET NAMES 'utf8mb4'

  • 關於utf8mb4 / utf8的相同考慮utf8mb4適用。

輸出

  • 如果您的應用程序將文本傳輸到其他系統,則還需要通知其字符編碼。 使用Web應用程序時,必須通知瀏覽器發送數據的編碼(通過HTTP響應標頭或HTML元數據 )。

  • 在PHP中,您可以使用default_charset php.ini選項,或手動發布Content-Type MIME頭,這只是更多的工作,但具有相同的效果。

輸入

  • 不幸的是,在嘗試存儲或在任何地方使用它之前,您應該驗證每個收到的字符串是否為有效的UTF-8。 PHP的mb_check_encoding()有訣竅,但你必須虔誠地使用它。 真的沒有辦法解決這個問題,因為惡意客戶可以用他們想要的任何編碼提交數據,而且我還沒有發現讓PHP可靠地為您做這件事的竅門。

  • 從我閱讀當前的HTML規範 ,下面的子項目不再是現代HTML的必要或者甚至是有效的。 我的理解是,瀏覽器將使用為文檔指定的字符集並提交數據。 但是,如果您的目標是舊版HTML(XHTML,HTML4等),這些點可能仍然有用:

    • 對於僅HTML5之前的HTML :您希望瀏覽器發送給您的所有數據都是UTF-8。 不幸的是,如果你唯一能夠可靠地做到這一點的方法是將accept-charset屬性添加到所有的<form>標籤中: <form ... accept-charset="UTF-8">
    • 對於僅HTML5之前的HTML :請注意,W3C HTML規範指出客戶端“應該”默認將表單發送回服務器,無論服務器使用什麼字符集,但這顯然只是一個建議,因此需要在每一個單獨的<form>標籤。

其他代碼注意事項

  • 顯然,所有你要服務的文件(PHP,HTML,JavaScript等)都應該用有效的UTF-8編碼。

  • 您需要確保每次處理UTF-8字符串時都要安全。 不幸的是,這是困難的部分。 您可能想要廣泛使用PHP的mbstring擴展。

  • PHP的內置字符串操作在默認情況下不是 UTF-8安全的。 對於普通的PHP字符串操作(如串聯),您可以安全地執行一些操作,但對於大多數情況,您應該使用等效的mbstring函數。

  • 要知道你在做什麼(閱讀:不要搞砸),你真的需要知道UTF-8以及它如何在盡可能低的水平上工作。 查看來自utf8.com任何鏈接,了解一切您需要了解的一切優質資源。


在我的情況下,我使用mb_split ,它使用正則表達式。 因此,我還必須通過執行mb_regex_encoding('UTF-8');手動確保正則表達式編碼是utf-8 mb_regex_encoding('UTF-8');

作為一個方面說明,我還通過運行mb_internal_encoding()發現內部編碼不是utf-8,並通過運行mb_internal_encoding("UTF-8");改變它mb_internal_encoding("UTF-8");


如果你希望MySQL服務器決定字符集,而不是PHP作為客戶端(舊的行為;在我看來,首選),嘗試在你的my.cnf添加skip-character-set-client-handshake ,在[mysqld] ,重啟mysql

如果您使用的不是UTF8,可能會造成麻煩。


我剛剛經歷了相同的問題,並在PHP手冊中找到了一個很好的解決方案。

我將所有文件編碼都改為UTF8,然後將我的連接上的默認編碼。 這解決了所有問題。

if (!$mysqli->set_charset("utf8")) {
    printf("Error loading character set utf8: %s\n", $mysqli->error);
} else {
   printf("Current character set: %s\n", $mysqli->character_set_name());
}

set_charset()


我唯一要添加到這些驚人的答案是強調保存您的文件在utf8編碼,我已經註意到瀏覽器通過設置utf8作為您的代碼編碼接受此屬性。 任何像樣的文本編輯器都會向你顯示這個,例如Notepad ++有一個文件添加菜單選項,它向你顯示當前的編碼,並允許你改變它。 對於我所有的php文件,我使用utf8沒有BOM。

有時候我有人問我為其他人設計的php / mysql應用程序添加utf8支持,我注意到所有文件都是用ANSI編碼的,所以我不得不使用ICONV來轉換所有文件,更改數據庫表以使用utf8 charset和utf8_general_ci collat​​e,在連接後向數據庫抽象層添加'SET NAMES utf8'(如果使用5.3.6或更早版本,否則必須在連接字符串中使用charset = utf8),並更改字符串函數以使用php多字節字符串函數等效。


我最近發現使用strtolower()可能會導致數據在特殊字符後被截斷的問題。

解決方案是使用

mb_strtolower($string, 'UTF-8');

mb_使用MultiByte。 它支持更多的字符,但總體來說會慢一點。


最好的答案非常好。 這是我必須在常規的debian / php / mysql設置上:

// storage
// debian. apparently already utf-8

// retrieval
// the mysql database was stored in utf-8, 
// but apparently php was requesting iso. this worked: 
// ***notice "utf8", without dash, this is a mysql encoding***
mysql_set_charset('utf8');

// delivery
// php.ini did not have a default charset, 
// (it was commented out, shared host) and
// no http encoding was specified in the apache headers.
// this made apache send out a utf-8 header
// (and perhaps made php actually send out utf-8)
// ***notice "utf-8", with dash, this is a php encoding***
ini_set('default_charset','utf-8');

// submission
// this worked in all major browsers once apache
// was sending out the utf-8 header. i didnt add
// the accept-charset attribute.

// processing
// changed a few commands in php, like substr,
// to mb_substr

就這些 !


除了在php.ini中設置default_charset ,您還可以在任何輸出之前使用代碼中的header()發送正確的字符集:

header('Content-Type: text/html; charset=utf-8');

在PHP中使用Unicode很容易,只要您意識到大多數字符串函數不適用於Unicode,並且有些可能會徹底破壞字符串 。 PHP認為“字符”長度為1個字節。 有時候這是可以的(例如, explode()只查找字節序列並將其用作分隔符 - 因此,查找的實際字符無關緊要)。 但是有些時候,當函數實際上是為了處理字符而設計的時候,PHP並不知道您的文本是否具有Unicode字符。

一個好的圖書館是phputf8 。 這將重寫所有“壞”函數,以便您可以安全地使用UTF8字符串。 有像mbstring擴展那樣的擴展,也嘗試為你做這件事,但我更喜歡使用該庫,因為它更便攜(但我寫了大眾市場產品,所以這對我很重要)。 但是無論如何,phputf8可以在幕後使用mbstring來提高性能。


首先,如果你在<5.3PHP然後沒有。 你需要解決很多問題。

我很驚訝沒有人提到intl庫, 它對 unicode字符字符串操作本地化等有很好的支持,見下文。

我將在PHPBenelux'14上引用關於伊麗莎白史密斯 slides中關於unicode支持的一些信息

INTL

好:

  • 包裝在ICU圖書館周圍
  • 標準化的區域設置,設置每個腳本的區域設置
  • 數字格式
  • 貨幣格式
  • 消息格式(替換gettext)
  • 日曆,日期,時區和時間
  • Transliterator
  • Spoofchecker
  • 資源包
  • 轉換器
  • 國際化域名支持
  • 字形
  • 整理
  • 迭代器

壞:

  • 不支持zend_multibite
  • 不支持HTTP輸入輸出轉換
  • 不支持函數重載

mb_string

  • 啟用zend_multibyte支持
  • 支持透明的HTTP輸入/輸出編碼
  • 為函數提供了一些包裝,如strtoupper

ICONV

  • 主要用於字符集轉換
  • 輸出緩衝區處理器
  • MIME編碼功能
  • 轉變
  • 一些字符串助手(len,substr,strpos,strrpos)
  • Stream Filter stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')

DATABASES

  • mysql:表和連接上的字符集和整理(不是整理)。 也不要使用mysql-msqli或PDO
  • postgresql:pg_set_client_encoding
  • sqlite(3):確保它是用unicode和intl支持編譯的

其他一些問題

  • 除非使用第三部分擴展名,否則不能在PHP和Windows中使用unicode文件名。
  • 如果使用exec,proc_open和其他命令行調用,則以ASCII格式發送所有內容
  • 純文本不是純文本,文件有編碼
  • 您可以使用iconv過濾器即時轉換文件

我會更新這個答案,以防事情改變添加的功能等等。





utf-8