日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

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

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

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

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

最近有好幾個朋友問我這個問題, 到底為什么?

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

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

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

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

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

一般情況下, 使用”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)) ?
  • ???{? ?
  • ???//**?調(diào)用libmysql的對應(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; ?
  • ?}?
  • 而對于mysql這個核心結(jié)構(gòu)的成員charset又有什么作用呢?

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

    對了, 你猜的沒錯, 就是mysql->charset.

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

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

    ?

  • <?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)); ?
  • ??>?
  • 因為, “慭”的gbk編碼低字節(jié)為5c, 也就是ascii中的”\”, 而因為除了mysql(i)_set_charset影響mysql->charset以外, 其他時刻mysql->charset都為默認值, 所以, 結(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的区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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