当前位置: 首页 > 编程日记 > 正文

转乱码UTF8和UTF-8网页编码

http://www.lovelucy.info/utf8-vs-utf-8.html#more-794

一、遇到的问题

曾经被字符集间复杂的转换搞怕了,正好新项目要求国际化,需要能够显示多种语言,于是一开始就规定统统使用 UTF-8 编码。

  1. 所有代码文件使用 UTF-8 编码存盘
  2. MySQL数据库所有表,所有字段设置 Collation (中文翻译为“整理”?)属性为 “utf8_general_ci”
  3. 所有页面输出
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

即便是这样,PHP 从数据库中读取内容,显示到网页上,还是出现了乱码,英文没问题,中文统统都是?问号。这样也行?艰苦卓绝的 debug 开始了……

开始debug

二、调查原因

MySQL 的字符集以繁多而著名,而其默认又是 latin1 的瑞典语编码,数据导入导出的时候一不留神就乱码了。

参考以上链接的官方文档,总结之:MySQL 对于字符集的支持细化到四个层次:

  1. server 服务器级
  2. database 数据库级
  3. table 表级
  4. connection 连接级

确保每一个级别都是使用的 UTF-8 编码。检查了一下,貌似我没有设置 connection 连接级。前 三种字符集级别只是规定了数据存储在 MySQL 中的编码格式,客户端读出数据后完全可以按照自己的意愿来解读数据。最后的 connection 连接级就是规定了客户端以什么编码来解析读取到的数据。也就是说,不论是 php 代码还是 DB 管理软件,在从 MySQL 读取数据之前都需要设定自己作为客户端的编码格式。

思考中

好吧,那么,在任何查询执行之前,先执行一句 set names utf-8。(使用框架进行开发的话,大多数框架应该会自动完成这一步,程序员一般只需要改配置文件)

$conn = mysql_connect($db_host, $db_user, $db_password);
if(!$conn)
die("Could not connect to mysql.");
mysql_select_db($db_name);
mysql_query("set names 'utf-8'");

刷新页面,仍旧乱码。

泪流满面

三、解决

只好再继续调查。¥#$…&%=^*&+%-#!@_@ 苦逼地一天就这样过去了……

咦,等等,官方文档里写的是 set names utf8 哦,和 set names utf-8 有啥区别么?赶紧试一下。

刷新页面,我擦,正常了。

WTF!!

搜了一下,发现被坑的人还真不少。UTF-8应该是标准的写法,在大多数场合都是有中间那个横杠的,只是MySQL这里偏偏就非主流去掉了横杠使用UTF8。

遇到同样问题,而本文未能帮你解决的,这篇乱码总结可能会帮到你。

//以下是讨论内容

今天看到大家在讨论,发现这是个很严重而又容易疏忽的问题,我以前也一直是用set names,遂记录下来,也提醒自己一把。

应该使用 mysql_ set_ charset(); 不要使用sql query来设置,有风险。

1.set names与mysql_set_charset有什么区别?

一般情况下, 使用”SET NAMES”就足够了, 也是可以保证正确的. 那么为什么手册又要说推荐使用 mysqli_set_charset(PHP>=5.0.5)呢。手册里面也没有明确说明。我们可以看下php扩展的源代码:

//php-5.2.11-SRC/ext/mysqli/mysqli_nonapi.c line 342
PHP_FUNCTION(mysqli_set_charset)
{
MY_MYSQL *mysql;
zval *mysql_link;
char *cs_name = NULL;
unsigned int len;
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis()
, “Os”, &mysql_link, mysqli_link_class_entry, &cs_name, &len) == FAILURE) {
return;
}
MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL*, &mysql_link, “mysqli_link”, MYSQLI_STATUS_VALID);
if (mysql_set_character_set(mysql->mysql, cs_name)) {
//** 调用libmysql的对应函数
RETURN_FALSE;
}
RETURN_TRUE;
}
可以看到php的mysql扩展是直接调用了mysql的mysql_set_character_set函数,接下来看看mysql的代码

//mysql-5.1.30-SRC/libmysql/client.c, line 3166:
int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name)
{
struct charset_info_st *cs;
const char *save_csdir= charsets_dir;
if (mysql->options.charset_dir)
charsets_dir= mysql->options.charset_dir;
if (strlen(cs_name) < MY_CS_NAME_SIZE &&
(cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
{
char buff[MY_CS_NAME_SIZE + 10];
charsets_dir= save_csdir;
/* Skip execution of "SET NAMES" for pre-4.1 servers */
if (mysql_get_server_version(mysql) charset= cs;
}
}
//以下省略
可以看到,除了调用real_query设置set names,还设置了mysql的charset变量。

2.这样有什么影响?

mysql_real_escape_string会受到影响,它与mysql_escape_string的区别就 是, 它会考虑”当前”字符集。如果仅仅使用set names,mysql_real_escape_string可能会失效。

例子:

$mysqli = new mysqli(“localhost”, “user”, “pass”, “test”, 3306);

/* check connection */
if (mysqli_connect_errno()) {
printf(“Connect failed: %s\n”, mysqli_connect_error());
exit();
}

$mysqli->query(‘SET NAMES gbk’); //使用set names设置字符集
$city = chr(0xbf).chr(0x5c); //0xbf5c是个有效的gbk字符,模拟用户输入
$city = $mysqli->real_escape_string ($city);//使用real_escape进行过滤

/* this query will fail, cause we didn’t escape $city */
if (!$mysqli->query(“INSERT into myCity(name) VALUES (‘$city’)”)) {
print “INSERT into myCity (name) VALUES (‘$city’)\n”;
printf(“Error: %s\n”, $mysqli->error);
}

var_dump($city);

var_dump($mysqli->client_encoding());

$mysqli->close();
3.解决方案

mysqli_set_charset函数对PHP和Mysql有版本要求,必须当mysql版本大于5,PHP版本大于5.0.5时,此函数才有 效。至于另一个mysql_set_charset函数,则更要求PHP版本大于5.2.3时才能有效。对于mysql4.1以上版本,使用”SET character_set_client=binary;”
推荐使用mysql_set_charset设置字符集的方案,只有在环境不允许的情况下,我们才推荐使用第二种binary编码的方案。但是无论在什么情况下,都禁止使用”SET NAMES”来作为设置字符集的操作。

转载于:https://www.cnblogs.com/xiaohong/archive/2012/03/13/2393327.html

相关文章:

linux管道的执行顺序

最近有个疑问&#xff0c;netstat -antup|head -500 类似这条命令中&#xff0c;是netstat 执行完然后截取前500条记录还是&#xff0c;netstat 与head 并行执行&#xff0c;netstat 执行完500条就不再继续&#xff1f; 最终答案由酷学园darkdanger大大提供&#xff1a; 唔…

为什么学习Python数据分析

为什么学习Python数据分析?这是很多人都比较关注的一个问题&#xff0c;Python编程语言近几年在互联网行业是非常火爆的&#xff0c;尤其是在人工智能这一领域&#xff0c;它会大大的提高我们的工作效率等等&#xff0c;具体来看看下面的详细介绍就知道了。 为什么学习Python数…

Python自动化开发学习6

引子 假设我们要在我们的程序里表示狗&#xff0c;狗有如下属性&#xff1a;名字、品种、颜色。那么可以先定义一个模板&#xff0c;然后调用这个模板生成各种狗。 def dog(name,d_type,color):data {name:name,d_type:d_type,color:color}return data d1 dog(小七,拉布拉多,…

Numpy入门教程:09. 输入和输出

背景 什么是 NumPy 呢&#xff1f; NumPy 这个词来源于两个单词 – Numerical和Python。其是一个功能强大的 Python 库&#xff0c;可以帮助程序员轻松地进行数值计算&#xff0c;通常应用于以下场景&#xff1a; 执行各种数学任务&#xff0c;如&#xff1a;数值积分、微分、…

第二语言综合征

前些天在看一本书&#xff0c;温伯格的《理解专业程序员》&#xff0c;其中提到有的程序员得了第二语言综合征——在学习第三、第四门语言的时候很容易&#xff0c;但是学习第二门简直能要了他们的命。我当时就确定我患了这个毛病&#xff0c;因为我一直想了解Java语言&#xf…

Python文件操作:finally子句的使用

finally子句与try-except语句连用时&#xff0c;无论try-except是否捕获到异常&#xff0c;finally子句后的代码都要执行&#xff0c;其语法格式如下&#xff1a; try: 可能出错的语句 ......except: 出错后的执行语句finally: 无论是否出错都会执行的语句 Python在处理文件时&…

Numpy入门教程:练习作业02

背景 什么是 NumPy 呢&#xff1f; NumPy 这个词来源于两个单词 – Numerical和Python。其是一个功能强大的 Python 库&#xff0c;可以帮助程序员轻松地进行数值计算&#xff0c;通常应用于以下场景&#xff1a; 执行各种数学任务&#xff0c;如&#xff1a;数值积分、微分、…

PowerShell 导入 SQL Server 的 PS 模块

接触过UNIX或者Linux 的朋友都知道此类系统有着功能强大、无所不能的壳程序,称之为Shell。微软公司于2006年第四季度正式发布PowerShell&#xff0c;它的出现标志着, 微软公司向服务器领域迈出了重要的一步, 不仅提供简便的图形化操作界面&#xff0c;同时提供类似于Unix, Linu…

ARM嵌入式操作系统启动

任何一个操作系统的启动都至少关注两个方面&#xff1a;&#xff11;&#xff0c;程序运行栈的初始化。&#xff12;&#xff0c;处理器外设的初始化。 在&#xff21;&#xff32;&#xff2d;&#xff56;&#xff16;以及以前的体系结构中&#xff0c;定义了七种模式分别为&…

Html5 aside标签的用法和作用

aside元素用来定义当前页面或者文章的附属信息部分&#xff0c;它可以包含与当前页面或主要内容相关的引用、侧边栏、广告、导航条等其他类似的有别于主要内容的部分。 aside元素的用法主要分为两种。 ● 被包含在article元素内作为主要内容的附属信息。 ● 在article元素之外使…

Numpy入门教程:10. 统计相关

背景 什么是 NumPy 呢&#xff1f; NumPy 这个词来源于两个单词 – Numerical和Python。其是一个功能强大的 Python 库&#xff0c;可以帮助程序员轻松地进行数值计算&#xff0c;通常应用于以下场景&#xff1a; 执行各种数学任务&#xff0c;如&#xff1a;数值积分、微分、…

Windows 7+Code::Blocks+wxWidgets实录(一)

环境配置篇 玩过Linux的人应该对Code::Blocks和wxWidgets并不陌生。 Code::Blocks是一款非常有名的代码编辑器&#xff0c;在linux下用不惯vim的话&#xff0c;这是个不错的选择。但千万不要把它和编译器混淆&#xff0c;CB本身并没有独立编译程序的功能&#xff0c;需要调用系…

技巧:两部解决U盘安装windows 7

第一步&#xff1a;准备一个4G的U盘并使用disk part 工具制作成引导盘1、在运行中输入cmd 回车2、在黑色的命令提示符界面中输入Diskpart3、插入U盘 并输入List Disk查看4、输入Select Disk 1 &#xff08;选择你的U盘所在的标识&#xff09;5、输入clean 清除旧的信息6、输入c…

报Java面授班有哪些优势

​ java技术在互联网行业的高速发展&#xff0c;让很多人都开始学习java技术&#xff0c;大家都想知道学习java技术面授班好还是网络班好&#xff0c;小编觉得当然是面授班比较好&#xff0c;下面小编就带大家来详细的了解一下报Java面授班有哪些优势? ​  报Java面授班有哪…

刻意练习:Python基础 -- Task13. datetime模块详解

datetime模块 datetime 是 Python 中处理日期的标准模块&#xff0c;它提供了 4 种对日期和时间进行处理的类&#xff1a;datetime、date、time 和 timedelta。 datetime类 class datetime(date):def __init__(self, year, month, day, hour, minute, second, microsecond, t…

关于java和c的选择结构和循环结构

java和c在这些结构上确实没区别。 另学会一个小技巧&#xff0c;在编辑界面选中段落之后按tab可以整体后移选中的段落&#xff0c;再按shifttab可以将选中的段落前移。转载于:https://www.cnblogs.com/hloli/archive/2012/03/15/2398675.html

从控制器到驱动器的WD——硬盘巨头启示录之西数篇

WD&#xff08;Western Digital&#xff0c;西部数据&#xff09;公司创立的时间比希捷公司还早近10年&#xff0c;但作为硬盘驱动器供应商的历史可不算长。1970年4月23日&#xff0c;一家名为General Digital&#xff08;通用数字&#xff09;的公司诞生了&#xff0c;其最初是…

java程序员入门先学什么开发者工具

学习java编程语言&#xff0c;那么开发工具是肯定少不了的&#xff0c;程序员入门基础中开发工具是一定要学会的&#xff0c;可以帮助开发者们提高开发效率、更优雅的写代码。由于开发者涉及的技术领域众多&#xff0c;以后端开发者的视角盘点平时可能用得到的工具&#xff0c;…

Numpy入门教程:11. 时间日期和时间增量

序言 什么是 NumPy 呢&#xff1f; NumPy 这个词来源于两个单词 – Numerical和Python。其是一个功能强大的 Python 库&#xff0c;可以帮助程序员轻松地进行数值计算&#xff0c;通常应用于以下场景&#xff1a; 执行各种数学任务&#xff0c;如&#xff1a;数值积分、微分、…

C#事件的发送方和接收方(订阅方)

C#事件的发送方和接收方&#xff08;订阅方&#xff09;基于Windows的应用程序也是基于消息的&#xff0c;Windows使用预定义消息与应用程序通讯。.NET Framework将Windows消息封装在事件中&#xff0c;可以把事件作为对象之间的通讯介质。事件发送方&#xff1a;发送事件的对象…

后台管理界面模版

http://www.cssmoban.com/cssthemes/houtaimoban/index_3.shtml转载于:https://www.cnblogs.com/hellojesson/p/7805516.html

选择PMP培训学校需要注意哪些

选择PMP培训学校需要注意哪些?如今各大职场对于项目管理这个岗位都是非常有需求的&#xff0c;有需求就有市场&#xff0c;PMP培训相关证书在市面上频繁出现&#xff0c;想要选择PMP培训学校需要注意哪些呢?来看看下面的详细介绍。 首先&#xff0c;我们来详细的了解一下什么…

绝对实用 NAT + VLAN +ACL管理企业网络

在企业中&#xff0c;要实现所有的员工都能与互联网进行通信&#xff0c;每个人各使用一个公网地址是很不现实的。一般&#xff0c;企业有1个或几个公网地址&#xff0c;而企业有几十、几百个员工。要想让所有的员工使用这仅有的几个公网地址与互联网通信该怎么做呢&#xff1f…

javascript 常用功能總結

1.路径符号的含义 src"/js/jquery.js"、"../"这个斜杠是绝对路径的意思&#xff0c;表示的是网站根目录. 其他的如"./ " 、 "../" 、 "jquery.js" 、 "js/jquery.js"等等表示的都是相对当前网页的路径&#xff0c…

学习资源:在线学习 Python(一)

背景 Python 是一种通用编程语言&#xff0c;其在科学计算和机器学习领域具有广泛的应用。如果我们打算利用 Python 来执行机器学习的代码&#xff0c;那么对 Python 有一些基本的了解就是至关重要的。 如果我们希望熟悉 Python 基本语法结构&#xff0c;但不希望在本地安装I…

什么BRIEF算法?BRIEF算法详解

BRIEF是一种特征描述子提取算法&#xff0c;并非特征点的提取算法&#xff0c;一种生成二值化描述子的算法&#xff0c;不提取代价低&#xff0c;匹配只需要使用简单的汉明距离(Hamming Distance)利用比特之间的异或操作就可以完成。因此&#xff0c;时间代价低&#xff0c;空间…

OpenLayers 动态添加标记(Marker)和信息窗(Popup)

方式一&#xff1a;使用marker方式 1、在地图上添加标记图层 var markers newOpenLayers.Layer.Markers("Markers"); map.addLayer(markers);//地图初始化添加 2、动态添加标记和Popup方法&#xff1a; //add map initial methodmap.events.register(click, this, fu…

Bag标签之中的一个行代码实行中文分词实例2

例1&#xff1a; 分词&#xff08;返回以逗号隔开每一个词带上引號的词组。gap","&#xff0c;quotes""或quotes"&#xff09; 单引號 <bag idpPage act2words namewords gap"," quotes"">我喜欢黄色高领T恤衫</bag>…

学习资源:在线学习 Python(二)

背景 Python 是一种通用编程语言&#xff0c;其在科学计算和机器学习领域具有广泛的应用。如果我们打算利用 Python 来执行机器学习的代码&#xff0c;那么对 Python 有一些基本的了解就是至关重要的。 如果我们希望熟悉 Python 基本语法结构&#xff0c;但不希望在本地安装I…

Java培训完可以应用在什么领域

​ java技术在互联网行业一直都是非常有发展前景的&#xff0c;很多小伙伴都想知道“Java培训完可以应用在什么领域”这个问题&#xff0c;下面小编就来为大家做下详细的介绍。 Java培训完可以应用在什么领域?java的应用非常的广泛&#xff0c;可以用来在开发软件工具、嵌入式…