深入理解mysql SET NAMES和mysql(i)_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) 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) "慭"
大家现在很清楚了吧?

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Interpretation of MyBatis dynamic SQL tags: Detailed explanation of Set tag usage MyBatis is an excellent persistence layer framework. It provides a wealth of dynamic SQL tags and can flexibly construct database operation statements. Among them, the Set tag is used to generate the SET clause in the UPDATE statement, which is very commonly used in update operations. This article will explain in detail the usage of the Set tag in MyBatis and demonstrate its functionality through specific code examples. What is Set tag Set tag is used in MyBati

Methods to delete elements: 1. Use delete() to delete the specified element from the Set object, the syntax is "setObj.delete(value);"; 2. Use clear() to delete all elements in the Set object, the syntax is "setObj.delete(value);" "setObj.clear();".

This article is based on the basics of Python and introduces how to use dict and set. The dict using the key-value storage structure is very useful in Python. It is important to choose an immutable object as the key. The most commonly used key is a string.

1. Overview of the Map Collection Framework The Map collection framework is a key-value pair data structure that allows you to use keys to find and store values. Each key in the Map is unique and can only be associated with one value. Common implementations in the Map collection framework include HashMap, TreeMap and LinkedHashMap. 1.HashMapHashMap is the most widely used Map implementation in Java. It stores data based on hash tables. HashMap has excellent performance, and the time complexity of search and insertion operations is O(1), but it does not guarantee the order of elements. Demo code: Mapmap=newHashMap

Preface There are two very similar methods in the commonly used collection interface List in Java: Eset(intindex,Eelement); voidadd(intindex,Eelement); both of these methods insert specified elements at specified positions in the collection, then What is the difference between these two methods? Next, let’s take a look at the differences and similarities between these two methods through ArrayList, our commonly used collection implementation. First, let’s take a look at the similarities between these two methods in ArrayList. They will insert new elements at specified positions in the collection, such as the following Example: #Insert an F in the 2nd position of the collection #Insert Listlist= through the add method

The set command syntax SETkeyid[FIELDnamevalue...][EXseconds][NX|XX](OBJECTgeojson)|(POINTlatlonz)|(BOUNDSminlatminlonmaxlatmaxlon)|(HASHgeohash)|(STRINGvalue) The set command is equivalent to the use of the hash command in redis. It is also a combination of key and id, but the difference is that Tile38's set command can also carry more other attributes, such as customizing the FIELD field, setting the EX validity period, etc., then we need to

The difference between Map and Set: key value and uniqueness: Map stores key-value pairs, and Set stores unique elements. Order: Among Maps and Sets, HashMap and HashSet are unordered sets, LinkedHashMap and LinkedHashSet are ordered sets, and TreeSet is sorted in order. Mutability: Map, LinkedHashMap and TreeSet are mutable collections, while HashSet and LinkedHashSet are immutable collections. Purpose: Map is used for key-value pair data, and Set is used for unique element data.

Common uses of set include creating a Set, adding elements, deleting elements, determining whether the Set is empty, getting the size of the Set, traversing the Set, finding elements, and set operations. Detailed introduction: 1. Create a Set, Setset=newHashSet(); 2. Add elements, set.add("java"); set.add("python");; 3. Delete elements, set.remove("java"); and so on.
