热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入理解mysqlSETNAMES和mysql(i)_set_charset的区别

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

最近公司组织了个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类似):
代码如下:
  //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;
  }   那mysql_set_character_set又做了什么呢?
代码如下:
  //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)   (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) <40100)
  return 0;
  sprintf(buff, "SET NAMES %s", cs_name);
  if (!mysql_real_query(mysql, buff, strlen(buff)))
  {
  mysql->charset= cs;
  }
  }
  //以下省略   我们可以看到, mysqli_set_charset除了做了”SET NAMES”以外, 还多做了一步:
代码如下:
  sprintf(buff, "SET NAMES %s", cs_name);
  if (!mysql_real_query(mysql, buff, strlen(buff)))
  {
  mysql->charset= cs;
  }   而对于mysql这个核心结构的成员charset又有什么作用呢?
  这就要说说mysql_real_escape_string()了, 这个函数和mysql_escape_string的区别就是, 它会考虑”当前”字符集. 那么这个当前字符集从哪里来呢?
  对了, 你猜的没错, 就是mysql->charset.
  mysql_real_string在判断宽字符集的字符的时候, 就根据这个成员变量来分别采用不同的策略, 比如如果是utf-8, 那么就会采用libmysql/ctype-utf8.c.
  看个实例, 默认mysql连接字符集是latin-1, (经典的5c问题):
代码如下:
    $db = mysql_connect('localhost:3737', 'root' ,'123456');
  mysql_select_db("test");
  $a = "\x91\x5c";//"慭"的gbk编码, 低字节为5c, 也就是ascii中的"\"
  var_dump(addslashes($a));
  var_dump(mysql_real_escape_string($a, $db));
  mysql_query("set names gbk");
  var_dump(mysql_real_escape_string($a, $db));
  mysql_set_charset("gbk");
  var_dump(mysql_real_escape_string($a, $db));
  ?>   因为, “慭”的gbk编码低字节为5c, 也就是ascii中的”\”, 而因为除了mysql(i)_set_charset影响mysql->charset以外, 其他时刻mysql->charset都为默认值, 所以, 结果就是:
代码如下:
  $ php -f 5c.php
  string(3) "慭\"
  string(3) "慭\"
  string(3) "慭\"
  string(2) "慭"   大家现在很清楚了吧?
推荐阅读
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 本文由编程笔记小编整理,介绍了PHP中的MySQL函数库及其常用函数,包括mysql_connect、mysql_error、mysql_select_db、mysql_query、mysql_affected_row、mysql_close等。希望对读者有一定的参考价值。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
author-avatar
邵crnich
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有