【问题标题】:How to fix syntax error in PHP when statement works fine in MySQL?当语句在 MySQL 中正常工作时,如何修复 PHP 中的语法错误?
【发布时间】:2019-02-08 22:11:54
【问题描述】:

我正在使用 PHP/MySQL 来存储从网页收集的数据。我来了

您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以获取正确的语法,以便在 'INSERT INTO Narrative_photos VALUES (`filename`, `narrative_id`) VALUES ('ash_02

当我将 PHP 生成的语句粘贴到 MySQL 控制台时,该语句运行正常。

这是 PHP 代码:

foreach ($files['pictures']['final_name'] as $key => $final_name) {
    $sql .= "INSERT INTO narrative_photos ";
    $sql .= "(`filename`, `narrative_id`) ";
    $sql .= "VALUES (";
    $sql .= "'" . db_escape($db, $final_name) . "', ";
    $sql .= "'LAST_INSERT_ID()'); ";
}

它会产生如下所示的东西:

INSERT INTO narrative_photos VALUES (`filename`, `narrative_id`) VALUES ('ash_020819-140257.png', 3);

如果我将它粘贴到 MySQL 中,它就可以工作。但是如果我注释掉 PHP 代码并替换:

 $sql .= "INSERT INTO narrative_photos VALUES (`filename`, `narrative_id`) VALUES ('ash_020819-140257.png', 3);";

它继续抛出 MySQL 错误。

我已经玩了几个小时了,但我不知道我的错误在哪里。我会欣赏第二双眼睛。谢谢!

编辑:这是上下文的整个函数。

function insert_narrative($narrative, $files) {
    global $db;

    $sql = "INSERT INTO narratives ";
    $sql .= "(date, positive_thing, what_you_did, goals, plan, entered_by, library_id) ";
    $sql .= "VALUES (";
    $sql .= "'" . db_escape($db, $narrative['sqldate']) . "', ";
    $sql .= "'" . db_escape($db, $narrative['positive_thing']) . "', ";
    $sql .= "'" . db_escape($db, $narrative['what_you_did']) . "', ";
    $sql .= "'" . db_escape($db, $narrative['goals']) . "', ";
    $sql .= "'" . db_escape($db, $narrative['plan']) . "', ";
    $sql .= "'" . db_escape($db, $narrative['entered_by']) . "', ";
    $sql .= "'" . db_escape($db, $_SESSION['library_id']) . "'";
    $sql .= "); ";

    if (!empty($files['pictures']['final_name'])) {
        foreach ($files['pictures']['final_name'] as $key => $final_name) {
            $sql .= "INSERT INTO narrative_photos ";
            $sql .= "(`filename`, `narrative_id`) ";
            $sql .= "VALUES (";
            $sql .= "'" . db_escape($db, $final_name) . "', ";
            $sql .= "LAST_INSERT_ID()); ";

        }
    }
    $result = mysqli_query($db, $sql);
    if ($result) {
        return true;
    } else {
        echo mysqli_error($db);
        db_disconnect($db);
        exit;
    }
}

编辑#2: 我刚刚意识到,与语法错误无关,我的方法是行不通的,因为 LAST_INSERT_ID 可能会为每个插入获取 id,而不仅仅是使用主表中的 id。我已经修改了函数,但在 SET @narrative_id 处仍然出现语法错误。这是代码。

$sql = "INSERT INTO narratives ";
$sql .= "(date, positive_thing, what_you_did, goals, plan, entered_by, library_id) ";
$sql .= "VALUES (";
$sql .= "'" . db_escape($db, $narrative['sqldate']) . "', ";
$sql .= "'" . db_escape($db, $narrative['positive_thing']) . "', ";
$sql .= "'" . db_escape($db, $narrative['what_you_did']) . "', ";
$sql .= "'" . db_escape($db, $narrative['goals']) . "', ";
$sql .= "'" . db_escape($db, $narrative['plan']) . "', ";
$sql .= "'" . db_escape($db, $narrative['entered_by']) . "', ";
$sql .= "'" . db_escape($db, $_SESSION['library_id']) . "'";
$sql .= "); ";
$sql .= "SET @narrative_id = LAST_INSERT_ID()";

if (!empty($files['pictures']['final_name'])) {
    foreach ($files['pictures']['final_name'] as $key => $final_name) {
        $sql .= "INSERT INTO narrative_photos ";
        $sql .= "(`filename`, `narrative_id`) ";
        $sql .= "VALUES (";
        $sql .= "'" . db_escape($db, $final_name) . "', ";
        $sql .= "@narrative_id); ";

    }
}

【问题讨论】:

  • 我认为你不想要这些引号'LAST_INSERT_ID()' 事实上,如果你可以完全删除它。因为密钥是在插入时自动完成的。基本上你将一个字符串传递给表的 Pkey 。这就是您收到错误的原因。
  • 删除引号并不能消除错误。 LAST_INSERT_ID() 的原因是我在此之前有一条 SQL 语句写入相关表。
  • 好吧,LAST_INSERT_ID 是一个 MySql 函数,就像在 DATE(datetime)WHERE 周围加上引号。
  • 您如何尝试运行查询 - 因为它可能是一个多查询?

标签: php mysql


【解决方案1】:

如果您尝试通过一个查询插入所有值,则无需每次都包含查询的 INSERT 部分,而只需添加一组新值。你可以使用这样的东西。请注意,LAST_INSERT_ID() 不应包含在引号中,因为这将插入文字字符串 "LAST_INSERT_ID()" 而不是值。

$sql  = "INSERT INTO narrative_photos (`filename`, `narrative_id`) VALUES ";
$values = array();
foreach ($files['pictures']['final_name'] as $final_name) {
    $values[] = "('" . db_escape($db, $final_name) . "', LAST_INSERT_ID())";
}
$sql .= implode(', ', $values);

备注

我假设您实际上希望所有这些文件名都以 narrative_id 中的相同值结束,这将链接回另一个表。

虽然从外观上看,这些值已经被过滤(我认为它们是实际的系统文件名),但代码仍然可能容易受到 SQL 注入的攻击。 This questionthis question 提供了一些关于如何使用带有参数数组的预处理语句的好建议。

【讨论】:

  • final_name 位似乎容易注入
  • $key 未使用。这是宣传准备好的陈述的好机会。
  • 等一下。预计这将如何运作? (我的意思是 OP 的编码尝试。)这是否有望继续从前一个插入的行中捕获新的 LAST_INSERT_ID?我担心这会存储倾斜/意外的行。
  • @mickmackusa 我的假设是所有文件都应该与另一个表中插入的id 相关联(假设字段名称为narrative_id)。这就是我采用这种方法的原因,因为它们都会得到相同的值。
  • 我不是在责怪你。我只是不知道这是否会按计划/预期进行。想想LAST_INSERT_ID() 做了什么。我在这里疯了吗?我没有进行任何本地测试来证实我的怀疑。我知道声明$values = array(); 是一种常见的习惯,但如果没有行,就不应该执行查询。
【解决方案2】:

我不明白你为什么将每一行连接到一个变量而不是只做一个完整的语句。此外,在您的示例中,您使用了两次VALUES,这是不正确的。我不明白为什么你在循环中创建 SQL 语句,但你从不执行它,这是你需要的。我不知道您使用的是什么 API,但这里有一个示例。

if (isset($files['pictures']['final_name'])) {
  foreach ($files['pictures']['final_name'] as $key => $final_name) {
    $sql = "INSERT INTO narrative_photos (`filename`, `narrative_id`) 
            VALUES ('".db_escape($db, $final_name)."', LAST_INSERT_ID())";
    if (!$mysqli->query($sql)) {
      echo "SQL failed: (".$mysqli->errno.") ".$mysqli->error;
    }
  }
} else {
  echo "final name does not exist";
}

【讨论】:

    猜你喜欢
    • 2012-04-24
    • 2016-03-05
    • 2020-10-30
    • 2019-08-21
    • 2017-08-03
    • 1970-01-01
    • 2013-07-18
    • 2012-08-21
    • 2012-07-22
    相关资源
    最近更新 更多