首頁 後端開發 php教程 mysqli_set_charset和SET NAMES使用抉择及优劣分析_php实例

mysqli_set_charset和SET NAMES使用抉择及优劣分析_php实例

May 17, 2016 am 09:07 AM
charset set

最近公司组织了个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 STDCALLmysql_set_character_set(MYSQL*mysql, const char *cs_name)
{
structcharset_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) "慭"大家现在很清楚了吧?
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1662
14
CakePHP 教程
1419
52
Laravel 教程
1311
25
PHP教程
1262
29
C# 教程
1234
24
詳解MyBatis動態SQL標籤中的Set標籤功能 詳解MyBatis動態SQL標籤中的Set標籤功能 Feb 26, 2024 pm 07:48 PM

MyBatis動態SQL標籤解讀:Set標籤用法詳解MyBatis是一個優秀的持久層框架,它提供了豐富的動態SQL標籤,可以靈活地建構資料庫操作語句。其中,Set標籤是用來產生UPDATE語句中SET子句的標籤,在更新作業中非常常用。本文將詳細解讀MyBatis中Set標籤的用法,以及透過具體的程式碼範例來示範其功能。什麼是Set標籤Set標籤用於MyBati

javascript怎麼從set刪除元素 javascript怎麼從set刪除元素 Jan 12, 2022 am 10:56 AM

刪除元素的方法:1、使用delete(),可從Set物件中刪除指定的元素,語法「setObj.delete(value);」;2、使用clear(),可刪除Set物件中的所有元素,語法「setObj.clear();」。

盤點Python編程中dict和set常用用法 盤點Python編程中dict和set常用用法 Jul 25, 2023 pm 04:52 PM

本文基於Python基礎,介紹如何去使用dict和set,使用key-value儲存結構的dict在Python中非常有用,選擇不可變物件作為key很重要,最常用的key是字串。

Java集合框架中Map與Set的實作與區別 Java集合框架中Map與Set的實作與區別 Apr 12, 2024 pm 10:12 PM

Map與Set的差別:鍵值與唯一性:Map儲存鍵值對,Set儲存唯一元素。順序:Map和Set中,HashMap和HashSet是無序集合,LinkedHashMap和LinkedHashSet是有序集合,TreeSet依序排序。可變性:Map、LinkedHashMap和TreeSet是可變集合,HashSet和LinkedHashSet是不可變集合。用途:Map用於鍵值對數據,Set用於唯一元素資料。

java中List中set方法和add方法的差別是什麼 java中List中set方法和add方法的差別是什麼 Apr 19, 2023 pm 07:49 PM

前言在Java中的常用的集合介面List中有兩個非常相似的方法:Eset(intindex,Eelement);voidadd(intindex,Eelement);這兩個方法都是在集合的指定位置插入指定的元素,那麼這兩個方法到底有什麼差別呢?接下來我們透過ArrayList這個我們常用集合實作來看這兩個方法的差異相同點首先我們來看看這兩個方法在ArrayList中的相同點他們都會在集合的指定位置插入新的元素,例如下面的範例:#在集合的第2位插入一個F#透過add方法插入Listlist=

Java Map 與其他集合架構的比較:優劣勢分析與應用場景指南 Java Map 與其他集合架構的比較:優劣勢分析與應用場景指南 Feb 19, 2024 pm 10:24 PM

一、Map集合框架概述Map集合框架是一種鍵值對資料結構,它允許您使用鍵來查找和儲存值。 Map中的每個鍵都是唯一的,並且只能與一個值相關聯。 Map集合框架中的常用實作包括HashMap、TreeMap和LinkedHashMap。 1.HashMapHashMap是Java中使用最廣泛的Map實現,它基於哈希表來儲存資料。 HashMap的效能優異,尋找和插入操作的時間複雜度為O(1),但它不保證元素的順序。示範程式碼:Mapmap=newHashMap

Springboot整合Tile客戶端之Set指令如何實現 Springboot整合Tile客戶端之Set指令如何實現 May 19, 2023 pm 01:37 PM

set指令語法SETkeyid[FIELDnamevalue...][EXseconds][NX|XX](OBJECTgeojson)|(POINTlatlonz)|(BOUNDSminlatminlonmaxlatmaxlon)|(HASHgeohash)|(STRINGvalue)set指令就相當於redis中的hash指令的使用,也是一個key和id的組合,但是不同的是,Tile38的set指令還可以攜帶更多的其他屬性,例如可以自訂FIELD字段,還可以設定EX有效期等等,那麼我們需要給

set的常見用法 set的常見用法 Oct 24, 2023 am 11:25 AM

set的常見用法有建立Set、新增元素、刪除元素、判斷Set是否為空、取得Set的大小、遍歷Set、尋找元素、集合運算。詳細介紹:1、建立Set,Setset=newHashSet();;2、新增元素,set.add("java"); set.add("python");;3、刪除元素,set.remove("java");等等。

See all articles