Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/236.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何测试数据库中是否存在行_Php_Mysql - Fatal编程技术网

Php 如何测试数据库中是否存在行

Php 如何测试数据库中是否存在行,php,mysql,Php,Mysql,我有一张名为user_bio的表。我已手动为用户名conor输入了一行: bio对用户来说是唯一的,显然,用户无法手动设置其bio以避免将其插入数据库中。考虑下面的场景: 以Conor身份登录。由于Conor在数据库中已经有一行,我只想运行一个更新查询来更新username等于Conor的字段。 以Alice的身份登录。因为Alice在数据库中没有与其用户名对应的行。然后我想运行一个插入查询。对于所有用户,所有用户都必须输入其详细信息,然后进行相应更新。 目前,当数据库中不存在行时,我正在努力将

我有一张名为user_bio的表。我已手动为用户名conor输入了一行:

bio对用户来说是唯一的,显然,用户无法手动设置其bio以避免将其插入数据库中。考虑下面的场景:

以Conor身份登录。由于Conor在数据库中已经有一行,我只想运行一个更新查询来更新username等于Conor的字段。 以Alice的身份登录。因为Alice在数据库中没有与其用户名对应的行。然后我想运行一个插入查询。对于所有用户,所有用户都必须输入其详细信息,然后进行相应更新。 目前,当数据库中不存在行时,我正在努力将数据插入数据库中

以下是我目前的做法:

$about_me = htmlentities(trim(strip_tags(@$_POST['biotextarea'])));
$new_studying = htmlentities(trim(strip_tags(@$_POST['studying'])));
$new_lang = htmlentities(trim(strip_tags(@$_POST['lang'])));
$new_rel = htmlentities(strip_tags(@$_POST['rel']));

if(isset($_POST['update_data'])){
    // need to check if the username has data already in the db, if so, then we update the data, otherwise we insert data.
        $get_bio = mysqli_query($connect, "SELECT * FROM user_bio WHERE username ='$username'");
        $row_returned = mysqli_num_rows($get_bio);
            $get_row = mysqli_fetch_assoc ($get_bio);
                $u_name = $get_row['username'];

        if ($u_name == $username){
            $update_details_query = mysqli_query ($connect, "UPDATE user_bio SET studying ='$new_studying', language ='$new_lang', 
                                                        relationship_status = '$new_rel', about_me = '$about_me' WHERE username ='$username'");
                echo "  <div class='details_updated'>
                            <p> Details updated successfully! </p>
                        </div>";
        } else {    
            $insert_query = mysqli_query ($connect, "INSERT INTO user_bio 
                                                    VALUES ('', '$age','$new_studying','$new_lang','$new_rel', '$username', '$about_me'");                                                          
                mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
                echo "  <div class='details_updated'>
                            <p> Details added successfully! $row_returned </p>
                        </div>";
        }

}
当以Conor身份登录时,更新查询工作正常。但同样,当以Alice身份登录时,INSERT不起作用。

MySQL支持INSERT。。。关于重复密钥更新类型的查询。所以,您不需要进行一些查询来检查php代码中行的存在性,只需添加正确的索引,并让您的DB处理这个问题

您可以阅读有关此类查询的信息

MySQL支持插入。。。关于重复密钥更新类型的查询。所以,您不需要进行一些查询来检查php代码中行的存在性,只需添加正确的索引,并让您的DB处理这个问题


您可以阅读有关此类查询的信息

以下是一些您可以执行的操作:

防止SQL注入 由于这是一个重要问题,下面提供的建议更正取决于这一点,因此我将其作为第一个需要解决的问题:

您应该使用而不是直接在SQL中注入用户提供的数据,因为这会使您的应用程序容易受到攻击。除了SQL字符串之外,任何动态参数都可以传递给SQL引擎,这样就不会发生注入

减少查询的数量 您不需要首先查询用户是否已经有bio记录。您可以立即执行更新,然后统计已更新的记录。如果没有,则可以发出insert语句

使用,您可以进一步将剩余的两个查询减少为一个查询。看起来是这样的:

在用户页面、学习、语言中插入, 关系状态、用户名、关于我 价值观 关于重复密钥 更新学习=价值观学习, 语言=价值俚语, 关系状态=价值关系状态, 关于我=关于我的价值; 只有在用户名上有唯一的密钥约束时,这才有效

使用此语句,您将受益于在一个事务中执行数据修改

还应注意上述文件中列出的一些注意事项

注意:正如您在评论中指出的,您不喜欢使用ON-DUPLICATE-KEY-UPDATE语法,我不会在下面建议的代码中使用它,而是使用2-query选项。尽管如此,我还是建议您尝试一下复制密钥更新构造。好处是不容忽视的

指定插入的列 您的INSERT语句可能已失败,原因是:

为自动递增键提供的空字符串值,在这种情况下会出现如下错误:

列“id”的整数值不正确

缺少列值,即表中的列多于您为其提供的值时

无论如何,最好在INSERT语句中显式指定列列表,并且不包括自动递增的列,如下所示:

在用户页面、学习、语言中插入, 关系状态、用户名、关于我 价值观 确保收到有关错误的通知 您可能还错过了上述错误或其他错误,因为您只有在执行查询后才设置了错误报告选项。因此,在执行任何查询之前执行该行:

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
并在此处添加:

error_reporting(E_ALL);
ini_set('display_errors', 1);
在生产环境中,您可能应该更加注意可靠的错误报告,因为在这样的环境中,您不希望在客户机中透露技术信息。但在开发过程中,您应该确保不会忽略意外错误

不要在数据库中存储HTML实体 最好不要在数据库中存储HTML实体。它们是特定于HTML的,您的数据库应该独立于HTML

相反,如果需要,在检索数据时插入这些实体。 在下面的代码中,我删除了对htmlentities的调用,但是您应该在代码中添加它们,在代码中选择并显示这些值

从模型中分离视图 这是正确的,但是您应该避免使用与数据库访问代码交织在一起的echo语句。将状态放在变量中,而不是显示在 pot可能是朝着正确方向迈出的第一步

建议代码 下面是一些未经测试的代码,它们实现了上述大多数问题

// Calls to htmlentities removed:
$about_me = trim(strip_tags(@$_POST['biotextarea']));
$new_studying = trim(strip_tags(@$_POST['studying']));
$new_lang = trim(strip_tags(@$_POST['lang']));
$new_rel = trim(strip_tags(@$_POST['rel']));
// Set the error reporting options at the start
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
if (isset($_POST['update_data'])) {
    // Do not query for existence, but make the update immediately 
    $update_stmt = mysqli_prepare ($connect,
            "UPDATE user_bio 
             SET    studying = ?, 
                    language = ?, 
                    relationship_status = ?, 
                    about_me = ? 
             WHERE  username = ?");
    mysqli_stmt_bind_param($update_stmt, "sssss", 
            $new_studying, $new_lang, $new_rel, $about_me, $username);
    mysqli_stmt_execute($update_stmt);
    $num_updated_rows = mysqli_stmt_affected_rows($update_stmt);
    mysqli_stmt_close($update_stmt);
    if ($num_updated_rows === 0) {
        $insert_stmt = mysqli_prepare ($connect,
                "INSERT INTO user_bio(age, studying, language,
                             relationship_status, username, about_me) 
                 VALUES (?, ?, ?, ?, ?, ?)");
        mysqli_stmt_bind_param($insert_stmt, "isssss", 
                $age, $new_studying, $new_lang, $new_rel, $username, $about_me);
        mysqli_stmt_execute($insert_stmt);
        mysqli_stmt_close($insert_stmt);
    }
    // Separate section for output
    $result = $num_updated_rows ? "Details updated successfully!"
                                : "Details added successfully!";
    echo "  <div class='details_updated'><p>$result</p></div>";
}

以下是您可以做的一些事情,以使其发挥作用:

防止SQL注入 由于这是一个重要问题,下面提供的建议更正取决于这一点,因此我将其作为第一个需要解决的问题:

您应该使用而不是直接在SQL中注入用户提供的数据,因为这会使您的应用程序容易受到攻击。除了SQL字符串之外,任何动态参数都可以传递给SQL引擎,这样就不会发生注入

减少查询的数量 您不需要首先查询用户是否已经有bio记录。您可以立即执行更新,然后统计已更新的记录。如果没有,则可以发出insert语句

使用,您可以进一步将剩余的两个查询减少为一个查询。看起来是这样的:

在用户页面、学习、语言中插入, 关系状态、用户名、关于我 价值观 关于重复密钥 更新学习=价值观学习, 语言=价值俚语, 关系状态=价值关系状态, 关于我=关于我的价值; 只有在用户名上有唯一的密钥约束时,这才有效

使用此语句,您将受益于在一个事务中执行数据修改

还应注意上述文件中列出的一些注意事项

注意:正如您在评论中指出的,您不喜欢使用ON-DUPLICATE-KEY-UPDATE语法,我不会在下面建议的代码中使用它,而是使用2-query选项。尽管如此,我还是建议您尝试一下复制密钥更新构造。好处是不容忽视的

指定插入的列 您的INSERT语句可能已失败,原因是:

为自动递增键提供的空字符串值,在这种情况下会出现如下错误:

列“id”的整数值不正确

缺少列值,即表中的列多于您为其提供的值时

无论如何,最好在INSERT语句中显式指定列列表,并且不包括自动递增的列,如下所示:

在用户页面、学习、语言中插入, 关系状态、用户名、关于我 价值观 确保收到有关错误的通知 您可能还错过了上述错误或其他错误,因为您只有在执行查询后才设置了错误报告选项。因此,在执行任何查询之前执行该行:

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
并在此处添加:

error_reporting(E_ALL);
ini_set('display_errors', 1);
在生产环境中,您可能应该更加注意可靠的错误报告,因为在这样的环境中,您不希望在客户机中透露技术信息。但在开发过程中,您应该确保不会忽略意外错误

不要在数据库中存储HTML实体 最好不要在数据库中存储HTML实体。它们是特定于HTML的,您的数据库应该独立于HTML

相反,如果需要,在检索数据时插入这些实体。 在下面的代码中,我删除了对htmlentities的调用,但是您应该在代码中添加它们,在代码中选择并显示这些值

从模型中分离视图 这是正确的,但是您应该避免使用与数据库访问代码交织在一起的echo语句。将状态放在变量中而不是当场显示它们可能是朝着正确方向迈出的第一步

建议代码 下面是一些未经测试的代码,它们实现了上述大多数问题

// Calls to htmlentities removed:
$about_me = trim(strip_tags(@$_POST['biotextarea']));
$new_studying = trim(strip_tags(@$_POST['studying']));
$new_lang = trim(strip_tags(@$_POST['lang']));
$new_rel = trim(strip_tags(@$_POST['rel']));
// Set the error reporting options at the start
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
if (isset($_POST['update_data'])) {
    // Do not query for existence, but make the update immediately 
    $update_stmt = mysqli_prepare ($connect,
            "UPDATE user_bio 
             SET    studying = ?, 
                    language = ?, 
                    relationship_status = ?, 
                    about_me = ? 
             WHERE  username = ?");
    mysqli_stmt_bind_param($update_stmt, "sssss", 
            $new_studying, $new_lang, $new_rel, $about_me, $username);
    mysqli_stmt_execute($update_stmt);
    $num_updated_rows = mysqli_stmt_affected_rows($update_stmt);
    mysqli_stmt_close($update_stmt);
    if ($num_updated_rows === 0) {
        $insert_stmt = mysqli_prepare ($connect,
                "INSERT INTO user_bio(age, studying, language,
                             relationship_status, username, about_me) 
                 VALUES (?, ?, ?, ?, ?, ?)");
        mysqli_stmt_bind_param($insert_stmt, "isssss", 
                $age, $new_studying, $new_lang, $new_rel, $username, $about_me);
        mysqli_stmt_execute($insert_stmt);
        mysqli_stmt_close($insert_stmt);
    }
    // Separate section for output
    $result = $num_updated_rows ? "Details updated successfully!"
                                : "Details added successfully!";
    echo "  <div class='details_updated'><p>$result</p></div>";
}

除了安全问题和糟糕的编码实践之外,您还可以做一些事情

您不需要比较名称来检查bio是否已经存在。您可以只计算返回的行数。如果大于零,则用户bio已存在

比较字符串时,==优先于==。你可以阅读它并找出原因,但这是第二个答案的例子

您应该认真研究“替换到”或“复制密钥更新”。只要使用这两种代码中的任何一种,根据您的用例选择一种,您就可以消除当前显示代码的一半以上。基本上,两者都将插入,如果记录已经存在,它们将更新。因此,您甚至不需要检查记录是否已经存在


除了安全问题和糟糕的编码实践之外,您还可以做一些事情

您不需要比较名称来检查bio是否已经存在。您可以只计算返回的行数。如果大于零,则用户bio已存在

比较字符串时,==优先于==。你可以读到它并找出原因 但这是第二个答案的例子

您应该认真研究“替换到”或“复制密钥更新”。只要使用这两种代码中的任何一种,根据您的用例选择一种,您就可以消除当前显示代码的一半以上。基本上,两者都将插入,如果记录已经存在,它们将更新。因此,您甚至不需要检查记录是否已经存在



为什么要使用mysql函数?它们已经被弃用很长一段时间了。。。。此外,不应在SQL字符串中插入用户提供的值。替换为HTML实体并不能防止SQL注入。@trincot-对不起,我在哪里使用过mysql函数?我似乎看不出来,也许我只是瞎了啊哈,但我正在使用mysqli。谢谢你的建议!事实上,我花了几个小时修改我的代码以确保它更安全:对不起,我以为我在你的代码中看到了mysql,但我一定是弄错了。我收回这一评论-请注意,@s_mart answer是一个不错的选择。你试过了吗?它将把你的PHP代码减少到现在的25%。好吧,我仍然认为你应该重新访问DUPLICATE KEY,但我已经提供了一个答案,将你的代码转换成SQL注入安全版本,该版本还可以处理更新/插入开关,只需一次查询。你为什么使用mysql_uu函数?它们已经被弃用很长一段时间了。。。。此外,不应在SQL字符串中插入用户提供的值。替换为HTML实体并不能防止SQL注入。@trincot-对不起,我在哪里使用过mysql函数?我似乎看不出来,也许我只是瞎了啊哈,但我正在使用mysqli。谢谢你的建议!事实上,我花了几个小时修改我的代码以确保它更安全:对不起,我以为我在你的代码中看到了mysql,但我一定是弄错了。我收回这一评论-请注意,@s_mart answer是一个不错的选择。你试过了吗?它将把你的PHP代码减少到现在的25%。好吧,我仍然认为你应该重新访问DUPLICATE KEY,但我已经提供了一个答案,将你的代码转换成SQL注入安全版本,该版本还可以处理更新/插入开关,只需一次查询。哇,这是一个非常有启发性的答案!我已经在上面测试了您的代码,更新同样工作正常,如果数据库中没有$username的行,那么仍然不会生成新行,因为$username试图添加其bio INSERT无效。我已经尝试过实现ON-DUPLICATE-KEY方法,但是UPDATE和INSERT都不能使用这种方法。还有,我确实对用户名有一个唯一的密钥约束。当你说它不起作用时,会发生什么?错误?回声部分是否显示成功添加的详细信息?你能加上错误报告吗;和ini设置“显示错误”,1;确保报告所有错误?因此,我目前以Alice身份登录,她在user_bio表中没有任何行。当我在Alice输入详细信息的表单上单击submit时,没有回音显示给我。数据库中也没有生成新行。更新时echo的详细信息已成功更新。好的,因此我添加了错误报告。我现在得到以下错误:1。mysqli_stmt_bind_参数:无法获取mysqli_stmt 2未捕获异常“mysqli_sql_exception”,消息为“未为准备好的语句中的参数提供数据”`3。mysqli_sql_异常:未为prepared语句中的参数提供数据。第二次mysqli_stmt_bind_param调用时,我的代码中出现错误:它使用了错误的语句变量。它必须作为第一个参数$insert\u stmt而不是$update\u stmt传递。请使用更正的版本重试。第二个错误是第一个错误的结果。哇,这是一个非常有教育意义的答案!我已经在上面测试了您的代码,更新同样工作正常,如果数据库中没有$username的行,那么仍然不会生成新行,因为$username试图添加其bio INSERT无效。我已经尝试过实现ON-DUPLICATE-KEY方法,但是UPDATE和INSERT都不能使用这种方法。还有,我确实对用户名有一个唯一的密钥约束。当你说它不起作用时,会发生什么?错误?回声部分是否显示成功添加的详细信息?你能加上错误报告吗;和ini设置“显示错误”,1;确保报告所有错误?因此,我目前以Alice身份登录,她在user_bio表中没有任何行。当我在Alice输入详细信息的表单上单击submit时,没有回音显示给我。数据库中也没有生成新行。更新时echo的详细信息已成功更新。好的,因此我添加了错误报告。我现在得到以下错误:1。mysqli_stmt_bind_参数:无法获取mysqli_stmt 2未捕获异常“mysqli_sql_exception”,消息为“未为准备好的语句中的参数提供数据”`3。mysqli_sql_异常:没有为prepared语句中的参数提供数据。我的代码在第二次mysqli_stmt_bind_param调用时出错:它使用了错误的 陈述变量。它必须作为第一个参数$insert\u stmt而不是$update\u stmt传递。请使用更正的版本重试。第二个错误是第一个错误的结果。