日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

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

發(fā)布時(shí)間:2025/6/15 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解SET NAMES和mysql(i)_set_charset的区别 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最近公司組織了個(gè)PHP安全編程的培訓(xùn), 其中涉及到一部分關(guān)于Mysql的”SET NAMES”和mysql_set_charset (mysqli_set_charset)的內(nèi)容:

說(shuō)到, 盡量使用mysqli_set_charset(mysqli:set_charset)而不是”SET NAMES”, 當(dāng)然, 這個(gè)內(nèi)容在PHP手冊(cè)中也有敘及, 但是卻沒(méi)有解釋為什么.

最近有好幾個(gè)朋友問(wèn)我這個(gè)問(wèn)題, 到底為什么?

問(wèn)的人多了, 我也就覺(jué)得可以寫(xiě)篇blog, 專(zhuān)門(mén)介紹下這部分的內(nèi)容了.

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

我之前的文章深入MySQL字符集設(shè)置中, 曾經(jīng)介紹過(guò)character_set_client/character_set_connection/character_set_results這三個(gè)MySQL的”環(huán)境變量”, 這里再簡(jiǎn)單介紹下,

這三個(gè)變量, 分別告訴MySQL服務(wù)器, 客戶(hù)端的編碼集, 在傳輸給MySQL服務(wù)器的時(shí)候的編碼集, 以及期望MySQL返回的結(jié)果的編碼集.

比如, 通過(guò)使用”SET NAMES utf8″, 就告訴服務(wù)器, 我用的是utf-8編碼, 我希望你也給我返回utf-8編碼的查詢(xún)結(jié)果.

一般情況下, 使用”SET NAMES”就足夠了, 也是可以保證正確的. 那么為什么手冊(cè)又要說(shuō)推薦使用mysqli_set_charset(PHP>=5.0.5)呢?

首先, 我們看看mysqli_set_charset到底做了什么(注意星號(hào)注釋處, mysql_set_charset類(lèi)似):

?

  • //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)) ?
  • ???{? ?
  • ???//**?調(diào)用libmysql的對(duì)應(yīng)函數(shù)????? ?
  • ???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)?<?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)?<?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; ?
  • ?}?
  • 而對(duì)于mysql這個(gè)核心結(jié)構(gòu)的成員charset又有什么作用呢?

    這就要說(shuō)說(shuō)mysql_real_escape_string()了, 這個(gè)函數(shù)和mysql_escape_string的區(qū)別就是, 它會(huì)考慮”當(dāng)前”字符集. 那么這個(gè)當(dāng)前字符集從哪里來(lái)呢?

    對(duì)了, 你猜的沒(méi)錯(cuò), 就是mysql->charset.

    mysql_real_string在判斷寬字符集的字符的時(shí)候, 就根據(jù)這個(gè)成員變量來(lái)分別采用不同的策略, 比如如果是utf-8, 那么就會(huì)采用libmysql/ctype-utf8.c.

    看個(gè)實(shí)例, 默認(rèn)mysql連接字符集是latin-1, (經(jīng)典的5c問(wèn)題):

    ?

  • <?php?? ?
  • ??$db?=?mysql_connect('localhost:3737',?'root'?,'123456'); ?
  • ??mysql_select_db("test");???? ?
  • ??$a?=?"\x91\x5c";//"慭"的gbk編碼,?低字節(jié)為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)); ?
  • ??>?
  • 因?yàn)? “慭”的gbk編碼低字節(jié)為5c, 也就是ascii中的”\”, 而因?yàn)槌薽ysql(i)_set_charset影響mysql->charset以外, 其他時(shí)刻mysql->charset都為默認(rèn)值, 所以, 結(jié)果就是:

  • $ php -f 5c.php
  • string(3) "慭\"
  • string(3) "慭\"
  • string(3) "慭\"
  • string(2) "慭
  • 大家現(xiàn)在很清楚了吧?

    轉(zhuǎn)載于:https://blog.51cto.com/jiedushi/482071

    總結(jié)

    以上是生活随笔為你收集整理的深入理解SET NAMES和mysql(i)_set_charset的区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。