我正在设置一个新服务器,并希望在我的 Web 应用程序中完全支持 UTF-8。我过去曾在现有服务器上尝试过此操作,但似乎总是最终不得不回退到 ISO-8859-1。这...
我正在设置一个新服务器,并希望在我的 Web 应用程序中完全支持 UTF-8。我过去曾在现有服务器上尝试过此操作,但似乎总是最终不得不回退到 ISO-8859-1。
我到底需要在哪里设置编码/字符集?我知道我需要配置 Apache、MySQL 和 PHP 才能做到这一点 — 是否有一些我可以遵循的标准清单,或者可以排除不匹配发生的位置故障?
这是用于新的 Linux 服务器,运行 MySQL 5、PHP 5 和 Apache 2。
数据库服务器的时区也是一个重要的设置。我建议使用 UTC(对于 MySQL,`set time_zone='+0:00``)作为服务器默认值。
数据存储 :
p1
p2
数据访问 :
p4
p5
【【p6】】
$dbh = new PDO('mysql:charset=utf8mb4');
【【p7】】
$mysqli->set_charset('utf8mb4'); // object oriented style mysqli_set_charset($link, 'utf8mb4'); // procedural style
【【p8】】
p9
p10
输出 :
Content-Type: text/html; charset=utf-8
default_charset
header()
json_encode()
JSON_UNESCAPED_UNICODE
输入 :
mb_check_encoding()
其他代码注意事项 :
p14
第15页
p16
p17
我没有错:COLLATE 意味着 CHARACTER SET。例如,请参阅 dev.mysql.com/doc/refman/5.0/en/charset-database.html。
请注意,MySQL 使用的语言与其他人不同。当 MySQL 说“utf8”时,它实际上意味着“某种奇怪的、弱智的 UTF-8 变体,由于天知道什么荒谬的原因,它被限制为三个字节”。如果您真的想要 UTF-8,您应该告诉 MySQL,您想要这个 MySQL 喜欢称之为 utf8mb4 的奇怪东西。不要费心去想“WTF!”。
@chazomaticus 你觉得我应该使用 mbstring 来处理英语吗....或者 strlen 就够了?那希腊语呢?
@chazomaticus 我的数据库已经存储了问号而不是希伯来语文本,那么我如何从问号中获取原始文本?
我想对 chazomaticus 的精彩回答 :
也不要忘记 META 标签(像这样,或者 它的 HTML4 或 XHTML 版本 ):
<meta charset="utf-8">
这看起来微不足道,但 IE7 之前曾给我带来过这个问题。
我做的一切都是正确的;数据库、数据库连接和 Content-Type HTTP 标头都设置为 UTF-8,并且它在所有其他浏览器中都运行良好,但 Internet Explorer 仍然坚持使用“西欧”编码。
原来是页面缺少 META 标签。添加该标签后问题就解决了。
W3C 实际上有一个相当大的 部分专门用于 I18N 。他们有许多与此问题相关的文章 - 描述了 HTTP,(X)HTML 和 CSS 方面的问题:
他们建议同时使用 HTTP 标头和 HTML 元标记(或者在 XHTML 作为 XML 的情况下使用 XML 声明)。
除了在 php.ini 中设置之外 default_charset 在任何输出之前使用代码 header() 发送正确的字符集
header('Content-Type: text/html; charset=utf-8');
只要您意识到大多数 字符串函数不适用于 Unicode,并且有些函数可能会完全破坏字符串 ,那么在 PHP 中使用 Unicode 就很容易了。PHP 认为 \'字符\' 的长度为 1 个字节。有时这是可以的(例如, explode() 仅查找字节序列并将其用作分隔符 - 因此您查找的实际字符并不重要)。但其他时候,当该函数实际上设计用于处理 characters ,PHP 不知道您的文本具有使用 Unicode 找到的多字节字符。
一个值得一试的好库是 phputf8 。它重写了所有“坏”函数,因此您可以安全地处理 UTF8 字符串。还有一些扩展,例如 mb_string 扩展,也可以为您完成此操作,但我更喜欢使用该库,因为它更易于移植(但我编写的是大众市场产品,因此这对我来说很重要)。但无论如何,phpputf8 可以在后台使用 mb_string 来提高性能。
警告: 此答案适用于 PHP 5.3.5 及更低版本。请勿将其用于 PHP 版本 5.3.6(2011 年 3 月发布)或更高版本。 与 Palec's answer to PDO + MySQL and broken UTF-8 encoding .
警告: 此答案适用于 PHP 5.3.5 及更低版本。请勿将其用于 PHP 版本 5.3.6(2011 年 3 月发布)或更高版本。
与 Palec's answer to PDO + MySQL and broken UTF-8 encoding .
时遇到一个问题 PDO ,答案是将其用于 PDO 连接字符串:
$pdo = new PDO( 'mysql:host=mysql.example.com;dbname=example_db', "username", "password", array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
进一步研究后发现,只有 5.3.6 之前的 PHP 版本才需要这样做。另请参阅:http://.com/a/4361485/2286722(尽管它们使用单独的 $dbh->exec(\'set names utf8\');;但我更喜欢这里介绍的方法)。顺便说一句,PHP 手册中也有类似的注释:php.net/manual/en/pdo.construct.php#96325。
另请参阅 Palec 对 PDO + MySQL 和损坏的 UTF-8 编码的回答。
在我的例子中,我使用的是 mb_split ,它使用正则表达式。因此,我还必须手动确保正则表达式编码为 UTF-8,方法是: mb_regex_encoding('UTF-8');
mb_split
mb_regex_encoding('UTF-8');
附注:我还通过运行发现 mb_internal_encoding() 内部编码不是 UTF-8,我通过运行更改了它 mb_internal_encoding("UTF-8"); .
mb_internal_encoding()
mb_internal_encoding("UTF-8");
首先,如果你使用的是 PHP 5.3 之前的版本,那么不行。你有很多问题需要解决。
我很惊讶没有人提到 intl 库,该库对 Unicode , 字素字符串 , 操作 , 本地化 等有很好的支持,见下文。
Elizabeth Smith PHPBenelux'14 slides 幻灯片 中关于 PHP 中 Unicode 支持的一些信息
好的:
坏的:
stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')
是的,没错。Mysqli 和 PDO 可以使用其原生驱动程序。如果您使用 --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd 选项编译 php,它们也可以使用 mysqlnd 驱动程序。
我要补充的是,这些令人惊叹的答案强调以 UTF-8 编码保存文件,我注意到浏览器接受此属性,而不是将 UTF-8 设置为代码编码。任何像样的文本编辑器都会向您显示这一点。例如, Notepad++ 有一个文件编码菜单选项,它会显示当前编码并允许您更改它。对于我的所有 PHP 文件,我都使用不带 8 的 UTF- BOM .
前段时间,有人让我为别人设计的 PHP 和 MySQL 应用程序添加 UTF-8 支持。我注意到所有文件都是用 ANSI 编码的,所以我不得不使用 iconv 转换所有文件,将数据库表更改为使用 UTF-8 字符集和 utf8_general_ci 排序,在连接后将“SET NAMES utf8”添加到数据库抽象层(如果使用 5.3.6 或更早版本。否则,您必须在连接字符串中使用 charset=utf8)并更改字符串函数以使用等效的 PHP 多字节字符串函数。
我最近发现使用 strtolower() 可能会导致特殊字符后数据被截断的问题。
strtolower()
解决方案是使用
mb_strtolower($string, 'UTF-8');
mb_ 使用 MultiByte。它支持更多字符,但总体来说速度较慢。
在 PHP 中,您需要使用 多字节函数 ,或者打开 mbstring.func_overload 。这样,如果您有占用多个字节的字符,那么像 strlen 这样的东西就可以工作。
您还需要确定响应的字符集。您可以像上面一样使用 AddDefaultCharset,也可以编写返回标头的 PHP 代码。(或者,您可以将 META 标记添加到 HTML 文档中。)
需要注意的是,由于上述 @JW 评论中提到的问题,mbstring.func_overload 功能从 PHP 7.2 开始被弃用。因此,最好的建议是:是的,您绝对应该使用 mbstring 函数,但不要使用过载功能让标准函数以多字节方式工作。
我刚刚遇到了同样的问题,并在 PHP 手册中找到了一个很好的解决方案。
我将所有文件的编码都改为 UTF8,然后将连接的默认编码也改为 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()); }
查看源代码