在Python中为MySQL转义Unicode字符串(避免出现exceptions.UnicodeEncodeError)

4

我正在使用Twisted在Python中异步访问数据库。我的代码如下:

from twisted.enterprise import adbapi
from MySQLdb import _mysql as mysql

...

txn.execute("""
    INSERT INTO users_accounts_data_snapshots (accountid, programid, fieldid, value, timestamp, jobid)
    VALUES ('%s', '%s', '%s', '%s', '%s', '%s')
""" % (accountid, programid, record, mysql.escape_string(newrecordslist[record]), ended, jobid))

在遇到®这个字符之前,这个方法是可行的,但是这个字符导致了线程抛出异常:`exceptions.UnicodeEncodeError: 'ascii' codec can't encode character u'\xae' in position 7: ordinal not in range(128)

然而,如果我不使用MySQLdb_mysql.escape_string(),当输入包含引号等内容时,会出现数据库错误(当然)。由于异常发生在访问数据库之前,因此数据库的排序似乎根本不重要。

有什么最好的方法可以转义这些内容而不会在unicode字符上抛出异常?理想的解决方案是可以将unicode字符传递给MySQL而不会对查询产生干扰;但是,剥离字符串中的unicode字符,用问号替换它们,搞乱它们或任何其他会停止崩溃的东西都是可以接受的。

2个回答

11

不要像这样格式化字符串。这是一个巨大的安全漏洞。自己无法正确地进行引用。不要试图。

使用“execute”的第二个参数。简单来说,不要使用txn.execute("... %s, %s ..." % ("xxx", "yyy")),而是使用txn.execute("... %s, %s ...", ("xxx", "yyy"))。注意逗号而不是百分号。在其他数据库或使用不同的数据库绑定时,你可能会使用不同于“%s”的字符,比如?:1, :2, :3:foo:, :bar:, :baz:,但思路是相同的。(如果你对替代方案感到好奇,可以查看DB-API 2.0文档中的paramstyle文档

我曾经写过关于这个的文章。那篇文章中的讨论可能会特别吸引你。

请让我强调一下,这是唯一正确的方法。你可能已经看过MySQL文档中讨论了各种引用字符串的方式。你可能已经在PHP中编写了没有传递数据库参数的正确设施的应用程序。我保证所有这些信息来源都是错误的,并且会导致严重和持续的安全问题:不要将参数插入到SQL字符串中。


1
不仅这个代码可以正常工作,而且现在我也不必手动转换日期时间对象为字符串了。非常感谢您。 - Andrew Gorcester

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接