PHP mysqli 插入时出现随机错误

PHP mysqli random error during insert

我使用 PHP 脚本将数据从 mysql 数据库迁移到另一个具有不同架构的 mysql 数据库。我目前正在处理的实体非常简单。它是用户数据。我的所有数据库表都有 utf8_general_ci 支持阿拉伯语文本的排序规则。

我可能会收到以下错误:

Failed to run query #14: (1064) You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ايمان مصطفى', '1425827057', 0, 0, 1, 'Africa/Cairo', '', 0)' at line 1

这里出乎意料的事情:当我在由于错误而停止之前删除新添加到目标数据库的记录并再次运行我的脚本时,我得到了同样的错误但是另一条记录!

在上述错误中,您可能会注意到查询中的阿拉伯名称 ايمان مصطفى 缺少两个单引号 ' 之一。但是,我确定我的脚本用单引号将值括起来,如下所示:

$sqlFormat = "INSERT INTO users (uid, name, pass, theme, signature, created, access, login, status, timezone, language, picture) VALUES ('%s', '%s', '%s', '', '%s', '%s', 0, 0, 1, '%s', '', 0)";
    $sql = sprintf($sqlFormat, $user['uid'], $user['name'], $user['pass'], $user['signature'], $user['created'], $user['timezone']);
    $res2 = mysqli_query($db2, $sql);
    if (!$res2) {
        echo "Failed to run query #$i: (" . $db2->errno . ") " . $db2->error;
        echo "\n";
        echo $sqlInsert;
        if ($db2->errno != 1062) {
            exit();
        }

编辑

这是一个随机错误的示例,该错误是通过 INSERT sql 语句传递给查询的打印输出生成的:

Failed to run query #4: (1064) You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'عبد العزيز كحيل', '1425828804', 0, 0, 1, 'Africa/Cairo', '', 0)' at line 1

INSERT INTO users (uid, name, pass, theme, signature, created, access, login, status, timezone, language, picture) VALUES ('149', 'عبد العزيز كحيل', 'U.GCK9X7@-w@lZQ5HZ=x}M(@a5D}<`Cdod13aJ8O/&&>0%w7jUrKm[bX\', '', 'عبد العزيز كحيل', '1425828804', 0, 0, 1, 'Africa/Cairo', '', 0)

您可能会注意到阿拉伯名称 عبد العزيز كحيل 正确地用两个单引号括起来表示 name 字段的值,但缺少 signature 的尾随单引号领域。

我的问题是:

我真的不能告诉你为什么会这样,我猜是这种语言的一些字符集问题。您的脚本是否保存为 UTF-8、您的数据库是否为 UTF-8 以及您的连接是否也保存为 UTF-8?

一种方法(我认为最好的方法)是使用 PreparedStatements。不要自己填充值,而是让数据库来完成这项工作。由于您已经在使用 sprintf,因此您将很容易理解 PreparedStatements 的工作原理,因为它们使用相似的语法并以相似的方式工作。不同的是,你不是直接填写你的值,而是将这个Query原样发送到数据库,然后一个一个地发送你的值。

看看 mysqli::prepare,示例显示了如何使用 mysqli 处理准备语句。