mysqli_set_charset和SET NAMES使用抉择及优劣分析_PHP
最近公司组织了个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) "慭"大家现在很清楚了吧?

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











MyBatis 動的 SQL タグの解釈: Set タグの使用法の詳細な説明 MyBatis は、豊富な動的 SQL タグを提供し、データベース操作ステートメントを柔軟に構築できる優れた永続層フレームワークです。このうち、Set タグは、UPDATE ステートメントで SET 句を生成するために使用され、更新操作でよく使用されます。この記事では、MyBatis での Set タグの使用法を詳細に説明し、特定のコード例を通じてその機能を示します。 SetタグとはMyBatiで使用するSetタグです。

要素を削除するメソッド: 1. delete() を使用して Set オブジェクトから指定した要素を削除します (構文は "setObj.delete(value);" です); 2. Clear() を使用して Set オブジェクト内のすべての要素を削除します。構文は「setObj.delete(value);」「setObj.clear();」です。

この記事は Python の基礎をベースに dict と set の使い方を紹介します. キーと値の格納構造を使用した dict は Python で非常に便利です. キーとして不変のオブジェクトを選択することが重要です. 最も一般的に使用されるキーは文字列です。

Java の一般的に使用されるコレクション インターフェイス List には、よく似たメソッドが 2 つあります: Eset(intindex,Eelement); voidadd(intindex,Eelement); これらのメソッドはどちらも、コレクション内の指定された位置に指定された要素を挿入します。これら 2 つの方法の間で?次に、一般的に使用されるコレクション実装である ArrayList を介して、これら 2 つのメソッドの違いと類似点を見てみましょう。まず、ArrayList 内のこれら 2 つのメソッドの類似点を見てみましょう。これらのメソッドは、指定された位置に新しい要素を挿入します。次のようなコレクション 例: #コレクションの 2 番目の位置に F を挿入 #add メソッドを使用して #Insert Listlist=

1. マップ コレクション フレームワークの概要 マップ コレクション フレームワークは、キーを使用して値を検索および保存できるようにするキーと値のペアのデータ構造です。マップ内の各キーは一意であり、1 つの値のみに関連付けることができます。 Map コレクション フレームワークの一般的な実装には、HashMap、TreeMap、LinkedHashMap が含まれます。 1.HashMapHashMap は Java で最も広く使用されている Map 実装であり、ハッシュ テーブルに基づいてデータを格納します。 HashMap は優れたパフォーマンスを備えており、検索および挿入操作の時間計算量は O(1) ですが、要素の順序は保証されません。デモコード: Mapmap=newHashMap

set コマンドの構文 SETkeyid[FIELDnamevalue...][EX秒][NX|XX](OBJECTgeojson)|(POINTlatlonz)|(BOUNDSminlatminlonmaxlatmaxlon)|(HASHgeohash)|(STRINGvalue) set コマンドは、hash コマンドの使用と同等です。これもキーと ID の組み合わせですが、違いは、Tile38 の set コマンドは、FIELD フィールドのカスタマイズ、EX 有効期間の設定など、他の属性も保持できることです。

set の一般的な使用法には、Set の作成、要素の追加、要素の削除、Set が空かどうかの判断、Set のサイズの取得、Set の走査、要素の検索、および set 操作が含まれます。詳細な導入: 1. Set を作成します、Setset=newHashSet(); 2. 要素を追加します、set.add("java"); set.add("python");; 3. 要素の削除、set.remove("java"); など。

1.ListList は、要素を繰り返したり、インデックスによって要素にアクセスしたりできる、Java コレクション フレームワークの順序付きコレクションです。 List の一般的な実装クラスには、ArrayList、LinkedList、Vector などがあります。以下は、ArrayList を使用して整数のセットを格納する方法を示しています。 importjava.util.ArrayList;publicclassArrayListDemo{publicstaticvoidmain(String[]args){//ArrayList オブジェクトの作成 ArrayListnumbers=newArr
