【问题标题】:Sanitizing Strings before inserting to DB在插入数据库之前清理字符串
【发布时间】:2013-06-16 13:43:06
【问题描述】:

尝试将数据插入我的 sqlite 数据库时出现以下错误:

"sqlite near "t": syntax error"

我不知道这是什么意思:-(

背景:我正在使用mysql_real_escape_string 来“清理”来自在线表单的数据(表单会提示用户在文本字段中输入他们的信息并按“提交”) - 这非常有效:它允许所有单引号和双引号字符被接受并无错误地输入数据库。

接下来,我的 iPhone 应用程序查询这个 DB 并解析传入的数据 - 有趣的是,我得到 \" 和 \' 到处都是(如:don\'t 或 \"The Odyssey\ ” 而不是不要或“奥德赛”)

为了解决这个问题,我使用[stringVar stringByReplacingOccurrencesOfString:@"\\" withString:@""] - 所以我基本上用无空格替换所有斜线 - 这非常有效(我得到:不要 +“The Odyssey”。)

但是,当我现在尝试将这个新下载和解析的数据写入我的 on-device sqlite 数据库时 - 应用程序崩溃了。而且我相当肯定这与所有单引号和双引号、斜杠以及谁知道还有什么有关。

为了测试,我创建了一些不包含任何这些棘手字符的快速虚拟数据,将其插入数据库(在运行时),一切正常 - 应用程序没有崩溃,并且设备上sqlite 数据库显示一切正常 - 所以我相当肯定我的 sqlite 数据库、我的 sql 语句等没有任何问题。它一定是下载的数据/字符串仍然以某种方式损坏。

不用说,我不是 SQL 专家——我基本上只知道勉强糊口的基础知识,并尝试边走边学。我对此进行了研究,并认为我找到了mysql_real_escape_string 的解决方案,但它似乎只能以一种方式工作 - 除非我需要往返解决方案。

有什么提示或建议吗?

========================================

编辑#1 - 这是我正在使用的代码 - 混合了建议的内容和我在这本 iPhone 书中找到的内容:

NSString *sqlString = [NSString stringWithFormat:@"INSERT OR REPLACE INTO '%@' ('%@', '%@', '%@', '%@') VALUES (?, ?, ?, ?)", tableName, @"Title", @"Source", @"Date", @"StoryCopy"];

NSLog(@"The sql string is = '%@'", sqlString);
const char *sql = [sqlString UTF8String];
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nil);
if (rc == SQLITE_OK) {
    sqlite3_bind_text(stmt, 0, [sTitle UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 1, [sSource UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, [sDate UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 3, [sCopy UTF8String], -1, SQLITE_TRANSIENT);
}

if (sqlite3_step(stmt) != SQLITE_DONE) {
    NSAssert(0, @"Error updating table!!!");
}

sqlite3_finalize(stmt);

问题在于它将值插入到不应插入的列中。它有点到处都是。有什么想法吗?

【问题讨论】:

  • 传递给 sqlite3_bind_xxx 函数的列索引以 1 开头,而不是 0。遗憾的是,sqlite3_column_xxx 函数的列索引是从 0 开始的。它令人困惑且容易出错。另外,为什么要对表名和列名使用字符串格式?只需将名称放在查询字符串中即可。并且名称不需要引用。
  • 我明白了 - 很高兴知道 - 我修复了它并且它现在运行良好(谢谢!)重新使用表和列名的字符串格式 - 我最初的目的是让这个方法足够灵活,这样我就可以在我的数据库中的任何表上调用它(因此是“tableName”) - 它们在它们中都有不同的列数。但是代码已经经历了相当多的编辑,因为:-)(就像你刚才的修复一样。)所以它有点混杂了各种垃圾。坦率地说,现在我很高兴让它在这张孤独的桌子上工作 - 如果我必须为每张桌子编写单独的方法 - 就这样吧:-)

标签: mysql objective-c sqlite escaping


【解决方案1】:

听起来您的查询执行不正确。没有必要先“消毒”任何东西。确保您不使用字符串格式来构建您的查询。相反,请正确使用sqlite3_bind_xxx 函数。

例子:

sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(dbHandle, "INSERT INTO table_name (field1, field2) VALUES (?, ?)", -1, &stmt, nil);
if (rc == SQLITE_OK) {
    sqlite3_bind_text(stmt, 1, [someValue UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, [otherValue UTF8String], -1, SQLITE_TRANSIENT);
}

其中someValue 和otherValue 是NSString 对象。文本可以包含任何 Unicode 文本。使用sqlite_bind_text 负责转义任何需要转义的字符。

稍后,当您使用 sqlite3_column_text 从查询中读取值时,您将返回原始文本。

【讨论】:

  • ... 这同样适用于 PHP 端:使用准备好的语句而不是可怕的 hack mysql_real_escape_string。
  • 好的,正在处理它 - 但是,当您写 sqlite3_statement *stmt; 时,您的意思是 sqlite3_stmt *stmt; 吗?
  • 好吧,它不再崩溃了——但它也不太正常。首先,我认为您的代码中还有另一个错误 - 在第二个 sqlite3_bind_text 中,我们不应该将 1 增加到 2 吗?等等?这些不是列号吗?
  • 复制并粘贴错字。固定的。我发布的代码旨在作为一个通用示例,为您指明正确的方向。如果您仍有问题,请使用更具体的详细信息(包括代码)更新您的问题。
猜你喜欢
  • 1970-01-01
  • 2023-03-21
  • 2014-01-15
  • 1970-01-01
  • 2010-11-19
  • 2016-04-23
  • 1970-01-01
  • 2012-06-02
  • 2017-03-19
相关资源
最近更新 更多