bool mysqli_set_charset ( mysqli $link , string $charset )

这应该是首选的用于改变字符编码的方法,不建议使用 mysqli_query()执行SQL请求的SET NAMES ...(如 SET NAMES utf8)。

用法:

<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "test"); /* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
} /* change character set to 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());
} $mysqli->close();
?>

最近公司组织了个PHP安全编程的培训, 其中涉及到一部分关于Mysql的”SET NAMES”和mysql_set_charset (mysqli_set_charset)的内容:

说到, 尽量使用mysqli_set_charset(mysqli:set_charset)而不是”SET NAMES”, 当然, 这个内容在PHP手册中也有叙及, 但是却没有解释为什么.

最近有好几个朋友问我这个问题, 到底为什么?

问的人多了, 我也就觉得可以写篇blog, 专门介绍下这部分的内容了.

首先, 很多人都不知道”SET NAMES”到底是做了什么,

我之前的文章深入MySQL字符集设置中, 曾经介绍过character_set_client/character_set_connection/character_set_results这三个MySQL的”环境变量”, 这里再简单介绍下,

这三个变量, 分别告诉MySQL服务器, 客户端的编码集, 在传输给MySQL服务器的时候的编码集, 以及期望MySQL返回的结果的编码集.

比如, 通过使用”SET NAMES utf8″, 就告诉服务器, 我用的是utf-8编码, 我希望你也给我返回utf-8编码的查询结果.

一般情况下, 使用”SET NAMES”就足够了, 也是可以保证正确的. 那么为什么手册又要说推荐使用mysqli_set_charset(PHP>=5.0.5)呢?

首先, 我们看看mysqli_set_charset到底做了什么(注意星号注释处, mysql_set_charset类似):

 1 //php-5.2.11-SRC/ext/mysqli/mysqli_nonapi.c line 342
2 PHP_FUNCTION(mysqli_set_charset)
3 {
4 MY_MYSQL*mysql;
5 zval*mysql_link;
6 char *cs_name = NULL;
7 unsigned int len;
8
9 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis()
10 , "Os", &mysql_link, mysqli_link_class_entry, &cs_name, &len) == FAILURE) {
11 return;
12 }
13 MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL*, &mysql_link, "mysqli_link"
14 , MYSQLI_STATUS_VALID);
15
16 if (mysql_set_character_set(mysql->mysql, cs_name)) {
17 //** 调用libmysql的对应函数
18 RETURN_FALSE;
19 }
20 RETURN_TRUE;
21 }

那mysql_set_character_set又做了什么呢?

 1 //mysql-5.1.30-SRC/libmysql/client.c, line 3166:
2 int STDCALLmysql_set_character_set(MYSQL*mysql, const char *cs_name)
3 {
4 structcharset_info_st *cs;
5 const char *save_csdir= charsets_dir;
6
7 if (mysql->options.charset_dir)
8 charsets_dir= mysql->options.charset_dir;
9
10 if (strlen(cs_name) < MY_CS_NAME_SIZE &&
11 (cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
12 {
13 char buff[MY_CS_NAME_SIZE + 10];
14 charsets_dir= save_csdir;
15 /* Skip execution of "SET NAMES" for pre-4.1 servers */
16 if (mysql_get_server_version(mysql) < 40100)
17 return 0;
18 sprintf(buff, "SET NAMES %s", cs_name);
19 if (!mysql_real_query(mysql, buff, strlen(buff)))
20 {
21 mysql->charset= cs;
22 }
23 }
24 //以下省略

我们可以看到, mysqli_set_charset除了做了”SET NAMES”以外, 还多做了一步:

1 sprintf(buff, "SET NAMES %s", cs_name);
2 if (!mysql_real_query(mysql, buff, strlen(buff)))
3 {
4 mysql->charset= cs;
5 }

而对于mysql这个核心结构的成员charset又有什么作用呢?

这就要说说mysql_real_escape_string()了, 这个函数和mysql_escape_string的区别就是, 它会考虑”当前”字符集. 那么这个当前字符集从哪里来呢?

对了, 你猜的没错, 就是mysql->charset.

mysql_real_string在判断宽字符集的字符的时候, 就根据这个成员变量来分别采用不同的策略, 比如如果是utf-8, 那么就会采用libmysql/ctype-utf8.c.

看个实例, 默认mysql连接字符集是latin-1, (经典的5c问题):

 1 <?php
2 $db = mysql_connect('localhost:3737', 'root' ,'123456');
3 mysql_select_db("test");
4 $a = "\x91\x5c";//"慭"的gbk编码, 低字节为5c, 也就是ascii中的"\"
5
6 var_dump(addslashes($a));
7 var_dump(mysql_real_escape_string($a, $db));
8
9 mysql_query("set names gbk");
10 var_dump(mysql_real_escape_string($a, $db));
11
12 mysql_set_charset("gbk");
13 var_dump(mysql_real_escape_string($a, $db));
14 ?>

因为, “慭”的gbk编码低字节为5c, 也就是ascii中的”\”, 而因为除了mysql(i)_set_charset影响mysql->charset以外, 其他时刻mysql->charset都为默认值, 所以, 结果就是:

1 $ php -f 5c.php
2 string(3) "慭\"
3 string(3) "慭\"
4 string(3) "慭\"
5 string(2) "慭"

大家现在很清楚了吧?

转载自:http://www.laruence.com/2010/04/12/1396.html

mysqli_set_charset和SET NAMES优劣分析的更多相关文章

  1. spark和strom优劣分析

    对于Storm来说:1.建议在那种需要纯实时,不能忍受1秒以上延迟的场景下使用,比如实时金融系统,要求纯实时进行金融交易和分析2.此外,如果对于实时计算的功能中,要求可靠的事务机制和可靠性机制,即数据 ...

  2. 小白学习mysql之存储过程的优劣分析以及接入控制

    存储过程的优劣 存储过程是一组实现特定功能的SQL语句集合,存储过程一经编译便存储在了服务器上,可以通过调用存储过程的名字以及传入相应的参数来使用存储过程.要高层次的掌握存储过程,不能觉得依葫芦画瓢, ...

  3. 地区picker 各选择器,优劣分析

    移动端选择器picker有很多,各大ui组件都有自己的picker,比如light7,HUI,MUI,jqueryUI等等.但是,我发现他们都有各种各样的问题.这次的地区选择,需要地区的省份+市+经纬 ...

  4. JAVA之多线程概念及其几种实现方法优劣分析

    1. 多线程 程序:指令集,静态的概念 进程:操作系统调动程序,是程序的一次动态执行过程,动态的概念 线程:在进程内的多条执行路径 Ps:单核的话进程都是虚拟模拟出来的,多核处理器才可以执行真正的多线 ...

  5. Dedecms手机站三种不同建设方法和优劣分析

    dedecms简单易用功能强大,是国内使用最多的cms建站系统,百度站长平台专门推出了“织梦移动化指南”,由此可见dedecms的影响力.织梦也是站长使用和学习最早的cms建站系统,解放了我的双手,让 ...

  6. Memcached与Redis对比及其优劣分析

    国外讨论 本文主要总结缓存Redis和Memcached的区别,总结之前先参考外国知乎上的一篇问答:<Is memcached a dinosaur in comparison to Redis ...

  7. 用rem实现WebApp自适应的优劣分析

    关于rem实现屏幕自适应布局的讨论还是比较多的,刚好我也看到使用rem实现自适应的web app,所以也来凑下热闹. 说起rem,免不了要联系到em.px,这里简单提提他们的定义和特点. 1. px: ...

  8. linux中exec和xargs命令的区别和优劣分析

    find的exec及ok命令 exec命令的格式为: exec command {} \; exec后面跟着的是操作命令,然后跟着{}表示每一个参数,然后空格,然后"\;".{}之 ...

  9. 网络层block,delegate之优劣分析

    正常情况下, block 缺点: 1.block很难追踪,难以维护 2.block会延长先关对象的生命周期 block会给内部所有的对象引用计数+1, 一方面会带来潜在的循环引用(retain cyc ...

随机推荐

  1. 如何使用robots不让百度和google收录

    如何使用robots不让百度和google收录   有没有想过,如果我们某个站点不让百度和google收录,那怎么办? 搜索引擎已经和我们达成一个约定,如果我们按约定那样做了,它们就不要收录. 这个写 ...

  2. Gimp制作圆角透明图片

    用蒙版制作圆角透明图片,步骤如下: 1,用Gimp(2.8版本)打开图片 2,在图层窗口右键当前图层创建蒙版 3,选择蒙版类型黑色(全透明) 4,结果如下 5,用圆角矩形选择工具选择图片,设置圆角半径 ...

  3. Cloud Foundry warden container 安全性探讨

    本文将从Cloud Foundry中warden container的几个方面探讨warden container的安全性. 1. warden container互訪 1.1.  互訪原理· 在Cl ...

  4. JavaScript 覆盖document.createElement 方法 解决window.close在火狐下不兼容问题)

    近期项目遇到了问题,有个asp.net web程序仅仅能在IE7 执行.如今xp都淘汰了,大家都用IE8-IE11,因此这个web app也须要升级 适应全部IE版本号.照成IE版本号不兼容的问题主要 ...

  5. 你应当知道的Java牛人

    Java领域有非常多著名的人物,他们为Java社区编写框架.产品.工具或撰写书籍改变了Java编程的方式. 本文是<最受欢迎的8位Java牛人>的2.0版本号. PS:排名不分先后.本文的 ...

  6. windows cmd: 打开windows系统程序或服务的常见命令

    Windows常用CMD命令 http://www.cnblogs.com/sbaicl/archive/2013/03/05/2944001.html 其实查找Windows自带程序的命令行很简单, ...

  7. oracle去除字符串中间的空格

    update AC01 A set A.AAC003 = REGEXP_REPLACE(A.AAC003, '( ){1,}', '') WHERE A.AAC002 IN (SELECT AAC00 ...

  8. 单色VGA显示verilogHDL通用代码

    今天做VGA,真是拼凑了好久啊.唉,总算完成了. 本来想偷懒移植,最后还是自己写的代码. //2015/12/13 //designer : pengxiaoen //function : vga c ...

  9. 7,C++ public, protected, private 继承的区别

    在某处看到一张图,简单明了的说明了三者的关系,很是佩服,遂记录下来. //公有继承 对象访问 成员访问 public --> public Y Y protected --> protec ...

  10. thinkphp 常用的查询

    php 常用的数据库查询方式: //根据where 条件查询,使用select()方法 访问:http://localhost/thinkphp2/index.php/Machine/search_i ...