php - 如何设置所有的方式通过utf-8传递?

  显示原文与译文双语对照的内容

我正在设置一个新服务器,并希望在我的web应用程序中完全支持 UTF-8. 我曾经在过去的服务器上尝试过,总是不得不回到 ISO-8859-1.

我需要在哪里设置编码/字符集? 我知道我需要配置apache、mysql和php这样做——有一些标准检查表我可以遵循,或者解决不匹配的地方发生?

这是一个新的Linux服务器,运行 MySQL 5,PHP 5和 Apache 2.

时间:

数据存储:

  • 指定数据库中所有表和文本列的utf8mb4 字符集。 这使得MySQL物理存储和检索在UTF-8中编码的值。 注意,mysql将隐式地使用 utf8mb4 编码如果 utf8mb4_* ( 没有任何显式字符集) 指定排序规则。

  • 在旧版本的MySQL ( <5.5.3 ) 中,不幸的是,你将不得不使用只支持Unicode字符子集的utf8 。 我希望我在开玩笑。

数据访问:

  • 在你的应用程序代码中( 例如。 在你使用的任何数据库访问方法中,你都需要将连接字符集设置为 utf8mb4 。 这样,MySQL在将数据交给应用程序时不会从原生UTF-8转换,反之亦然。

  • 有些驱动程序提供了自己的配置连接字符集的机制,它们都更新了它自己的内部状态,并通知MySQL在connection—this上使用的编码通常是首选的方法。 在PHP中:

    • 如果你正在使用pdo抽象层使用php≥ 5.3.6,你可以指定 charsetDSN :

      
      $dbh = new PDO('mysql:charset=utf8mb4');
      
      
    • 如果你使用的是 i,你可以调用 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的同样考虑同样适用于。

输出:

  • 如果你的应用程序向其它系统发送文本,它们也需要得到字符编码的通知。 对于web应用程序,必须通知浏览器发送数据的编码。

  • 在PHP中,你可以使用 default_charset php.ini 选项,或者手动发出 Content-Type MIME头,这只是工作,但具有相同的效果。

输入:

  • 不幸的是,在尝试存储或者使用任何接收的字符串之前,你应该验证每个接收的字符串是有效的UTF-8. php mb_check_encoding() 能够奏效,但你必须虔诚地使用它。 真的是没有办法在这个,恶意的客户可以在他们想要的任何编码提交数据,我还没有找到一个方法让php可靠地为你做这个。

  • 从我的阅读当前html规范以下sub-bullets不再是必要的甚至是有效的对现代html。 我的理解是浏览器将在为文档指定的字符集中处理和提交数据。 但是,如果你针对的是旧版本的HTML ( XHTML,HTML4,等等 ),这些点可能仍然有用:

    • HTML5前的HTML 仅: 你希望浏览器将所有发送给你的数据都发送给 UTF-8. 不幸的是,如果你通过可靠的方式进行操作,那么将 accept-charset 属性添加到所有 <form> 标记: <form.. . accept-charset="UTF-8">
    • HTML5前的HTML 仅: 注意,w3chtml规范说客户"应该应该"默认在任何形式发送回服务器字符集服务器服务,但显然这只是一个建议,因此需要明确在每一个 <form> 标签。

其他代码考虑 :

  • 显然,你要为( PHP,HTML,JavaScript,等等 ) 提供的所有文件都应该编码为有效的UTF-8.

  • 你需要确保每次处理UTF-8字符串时,都会安全地执行。 不幸的是,这是最难的部分。 你可能会想要大量使用 php mbstring 扩展。

  • 内置的php字符串操作不是默认 UTF-8安全。 有些事情你可以安全地与普通php字符串操作( 像连接一样), 但是对于大多数事情你应该使用等效 mbstring 函数。

  • 要了解你正在做什么( 阅读: 不要混淆它,你需要知道UTF-8以及它如何在最低的级别上工作。 查看来自 utf8.com的任何链接,了解一些好的资源,了解你需要了解的所有信息。

我想向 chazomaticus添加一个内容excellent优秀答案:

不要忘记META标记( 像这样,或者或者它的XHTML版本):


<meta charset="utf-8">

这似乎微不足道,但IE7给了我一些问题。

我做的一切都是正确的;数据库,数据库连接和 Content-Type HTTP头都被设置为 UTF-8,并且在所有其他浏览器中都能正常工作,但是 IE 仍然坚持使用"西欧西欧"编码。

结果页面丢失了META标记。 添加解决了问题。

编辑:

W3C实际上有一个相当大的节,专门用于 i18n 。 他们有许多与这个问题相关的文章- 描述 HTTP,( X )的HTML和CSS方面:

他们建议使用HTTP报头和HTML元标记( 或者XML声明,以XHTML为例) 。

除了设置 default_charset php.ini, 你可以发送正确的字符集使用 header() 从内部代码,在任何输出:


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

在php中使用unicode是很容易的,只要你意识到大多数不使用unicode字符串函数,和一些字符串完全可能变形。 PHP认为"字符"是 1字节长。 有时这很好( 例如 explode() 只查找一个字节序列,并将它用作分隔符 --,这样它就不重要了) 。 但其他时候,当函数实际上是旨在字符,php已经不知道课本multi-byte发现unicode字符。

要签入的一个好库是 phputf8 。 这将重写所有"错误"函数,这样你就可以安全地使用UTF8字符串。 还有像mbstring扩展这样的扩展,试图为你做这些,但是我更喜欢使用库,因为它更便携。 但是phputf8可以在幕后使用 mbstring,从而提高性能。

旧主题,我知道。发现了一个使用PDO的问题,答案是将这个问题用于PDO连接字符串:


$pdo = new PDO(
 'mysql:host=mysql.example.com;dbname=example_db',
"username",
"password",
 array(PDO::MYSQL_ATTR_INIT_COMMAND =>"SET NAMES utf8"));

这个从网站我是下来,能够使用谷歌缓存幸运的得到它。

在我的例子中,我使用 mb_split,它使用 正规表达式 。 因此,我也不得不手工地确保 正规表达式 编码是 utf-8

顺便一提,我还通过运行 mb_internal_encoding() 发现内部编码不是 utf-8,我通过运行 mb_internal_encoding("UTF-8"); 更改了它。

首先如果你在 <5.3 PHP中,那么没有。 你有很多问题要解决。

令我感到惊讶,没有提到 intl 库,一个具有良好支持 unicode, 字母,字符串操作,本地化和更多的,见下图。

我将引用一些信息关于unicode支持php的伊丽莎白的史密斯幻灯片phpbenelux" 14

英镑

很好:

  • ICU库周围的包装器
  • 标准化区域设置,每个脚本设置区域设置
  • 数字格式
  • 货币格式
  • 消息格式( 替换 gettext )
  • 日历,日期,时区和时间
  • Transliterator
  • Spoofchecker
  • 资源束
  • 转换器
  • IDN支持
  • Graphemes符
  • 排序规则
  • 迭代器

错误:

  • 不支持 zend_multibite
  • 不支持HTTP输入输出转换
  • 不支持函数重载

mb_string

  • 启用zend_multibyte支持
  • 支持透明的HTTP/输出编码
  • 为funtionallity提供一些包装,比如 strtoupper
  • 字符集转换的主要内容
  • 输出缓冲区处理程序
  • mime编码功能
  • 转换
  • 一些字符串助手( len,substr,strpos,strrpos )
  • 流过滤器 stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')

数据库

  • MySQL: 表和连接( 不是排序规则)的字符集和排序规则。 也不要使用 MySQL - msqli或者 PDO
  • PostgreSQL: pg_set_client_encoding
  • sqlite(3): 确保它是用unicode和国际化支持编译

其他陷阱

  • 你不能将unicode文件名用于PHP和 Windows,除非你使用的是 3 rd的扩展。
  • 如果你使用 exec,proc_open和其他 命令行 调用,则将所有内容都用ASCII发送
  • 纯文本不是纯文本,文件有编码
  • 你可以使用iconv过滤器随时转换文件

我将更新这个答案,以防改变的特性等等。

在PHP中,你需要使用多字节函数,或者打开 mbstring.func_overload 。 这样,像strlen这样的东西可以工作,如果你有多个字节的字符。

你还需要识别你的响应的字符集。 你可以使用 AddDefaultCharset,也可以使用PHP代码,或者编写返回标题的代码。 ( 或者你可以在HTML文档中添加META标记。)

好的目标从开始基于你的网站的性质,我已经找到了很多关于这个的资源- 你不是第一个处理它的人,当然。

神秘PHP6应该把所有这些拉直?

你可以将utf-8设置为服务器级MySQL的全局默认字符集,它将默认为更细粒度的级别。

我最近发现,使用 strtolower() 可能导致问题的特殊字符后数据截断。

解决方案是使用 mb_strtolower($string,'UTF-8');

( 速度较慢,但它是一个解决方案)

PHP中的Unicode支持仍然是一个巨大的混乱。 虽然能够将一个ISO8859字符串( 它在内部使用) 转换为utf8,它缺乏的能力处理unicode字符串本身,这意味着所有的字符串处理函数会损坏和腐败你的字符串。 因此,你必须使用单独的库来支持适当的utf8支持,或者重写所有的字符串处理函数。

最简单的部分是指定字符集在http头和数据库等,但都不重要如果php代码不输出有效utf8. 这就是最难的部分,PHP在那里几乎没有帮助。 (我想PHP6应该修复这个最糟糕的,但这仍然是一个消磨时间)

...