1

我正在使用mysqlclient,

在我的一个查询中,如下所示

sprintf (query, "select user from pcloud_session where id = '%s'", sid);

这里有一段时间这个 sid 像例子一样用 % 登录

2Cq%yo4i-ZrizGGQGQ71eJQ0

但是当有这个 % 这个查询总是失败时,我想我必须逃避这个 %,但是如何?

我尝试使用 \ 和 %% ,但这两个都不起作用,请在这里帮助我

更新:

当使用 session.hash_bits_per_character = 6 时,在 php session 中,默认字符集包含一个字符(逗号),它将始终被 urlencoded(这里是 %2C)。这会导致 cookie 值中包含此 %2C,但会话 db 中包含逗号而不是逗号。关于解决这个问题的任何想法?..抱歉造成混淆

谢谢

4

3 回答 3

2

没有必要'%'在 MySQL 查询文本中转义文字。

当您说查询“总是失败”时,是对mysql_query返回错误的函数的调用吗?它是返回 SQL 异常代码,还是只是不返回您期望的结果集(行)?

对于调试,我建议您query在调用sprintf. 我们希望字符串的内容是:

select user from pcloud_session where id = '2Cq%yo4i-ZrizGGQGQ71eJQ0'

而且我没有看到该 SQL 构造有任何问题(假设该id列存在于pcloud_session并且是字符数据类型。即使 id 被定义为整数类型,该语句通常也不会引发异常,字符串文字只是解释为 2 的整数值。)

在 sprintf 的目标格式中包含 '%' 文字应该没有问题。在 MySQL 查询文本中包含 '%' 文字应该没有问题。

(当然,我假设这sid是由函数调用填充的mysql_real_escape_string。)


同样,我建议您query在调用 sprintf 之后回显 的内容。我还建议您确保没有其他代码与该字符串的内容混为一谈,这是作为参数传递给mysql_query函数的实际字符串。(如果您正在使用该mysql_real_query函数,请确保您传递了正确的长度。)


更新

Oxi 说: “它没有返回 SQL 异常代码,只是没有返回我期望的结果 [set]。我确实打印了查询,它打印了 % 。”

@Oxi

这里有一大堆问题可能会帮助您找出问题所在。

您是否从 mysql 命令行客户端运行了该查询文本的测试,并返回您期望的行?

id列是否定义为长度为(至少)24 个字符的 VARCHAR(或 CHAR)?列上的排序规则设置为不区分大小写,还是区分大小写?

show create table pcloud_session ;

(我没有看到任何会导致字符集转换出现问题的字符,尽管如果您的应用程序与数据库字符集编码不匹配,这可能是问题的根源。)

您是否使用 LIKE 谓词针对该 id 列测试查询?

SELECT id, user FROM pcloud_session WHERE id LIKE '2Cq\%yo4i-%' ESCAPE '\\'
 ORDER BY id LIMIT 10 ;

SELECT id, user FROM pcloud_session WHERE id LIKE '2Cq%'
 ORDER BY id LIMIT 10 ;

当您期望一行时,您是否没有返回任何行?您是否返回了太多行,或者您得到的行与您期望的行不同?

id对于一列来说,这是一个奇怪的值。起初,它看起来好像该值是以 base-64 编码表示的,但它不是任何标准编码,因为它包含 '%' 和 '-' 字符。

于 2012-12-20T18:40:00.257 回答
0

如果您打算在没有接口库的情况下在 C 中执行此操作,则必须使用mysql_real_escape_string正确的 SQL 转义。

在 MySQL中使用 '% inside of a string, though, as the only context in which it has meaning is either directly inprintf type functions or as an argument toLIKE` 应该没有任何本质上的错误。

事实证明这很烦人,但这是绝对必要的。这将使您的代码变得更加复杂,这就是为什么在 C 中使用低级 MySQL 通常是一个坏主意。C++ 包装器将为您提供更多支持。

于 2012-12-20T18:45:33.717 回答
0

你真的不应该自己逃避字符串。最安全的选择是让 MySQL API 为您处理它。

对于最大长度为 n 的字符串,首先分配长度为 2*n+1 的字符串:

int sidLength = strlen(sid);
// worst-case, we need to escape every character, plus a byte for the ASCIIZ
int maxSafeSidLength = sidLength * 2 + 1;
char *safeSid = malloc(maxSafeSidLength);

// copy "sid" to "safeSid", escaping as appropriate
mysql_real_escape_string(mysql, safeSid, sid, sidLength);


// build the query
// ...

free(safeSid);

dev.mysql.com上的页面上有一个更长的示例mysql_real_escape_string,他们在其中构建了整个查询字符串,但上述方法应该适用于向 sprintf 提供 safeSid。

于 2012-12-20T18:49:47.767 回答