【问题标题】:Update database table row if a qualifying token is provided如果提供了合格令牌,则更新数据库表行
【发布时间】:2022-08-04 04:40:18
【问题描述】:

我的代码工作正常,但是这个高效的代码,就像第 16 行(注释)一样吗?我正在考虑使用$row 并与上面提到的变量进行比较,而不是编写另一个 SQL 查询。

我尝试使用变量和$row[\'field name\'],但它抛出了一个错误:

尝试访问 null 类型值的数组偏移量

代码

<?php
    require(\'../private/autoload.php\');
    if(isset($_GET[\'token\'])){
        $msg = \"Email verified successfully, thank you.\";
        $token = $_GET[\'token\'];
        $email_status = \"active\";
        $sql = \"SELECT `email_token`, `email_status` FROM `users` where `email_token` = ? AND `email_status` = \'inactive\' LIMIT 1\";
        $stmt = $conn->prepare($sql);
        $stmt->bind_param(\"s\", $token);
        $stmt->execute();
        $result = $stmt->get_result();
        $exist = $result->num_rows;
        if($exist == 0 ){

            // $row = $result->fetch_array(MYSQLI_ASSOC);
        $sql = \"SELECT `email_token`, `email_status` FROM `users` where `email_token` = ? AND `email_status` = ? LIMIT 1\";   // Line 16
            $stmt = $conn->prepare($sql);
            $stmt->bind_param(\"ss\", $token, $email_status);
            $stmt->execute();
            $result = $stmt->get_result();
            $exist = $result->num_rows;
            if($exist == 1){
            ?>
                <script>
                    alert(\"Email already verified.\");
                    window.location = \"../public/index.php\";
                </script>;

            <?php exit(); ?>

            <?php }else{ ?>
                <script>
                    alert(\"User not found.\");
                    window.location = \"../public/index.php\";
                </script>;
          <?php  }

        }else{
            $sql = \"UPDATE `users` SET `email_status`= ? where `email_token` = ?  LIMIT 1\";
            $stmt = $conn->prepare($sql);
            $stmt->bind_param(\"ss\", $email_status, $token);
            $stmt->execute();
            $stmt->close();
            $_SESSION[\'msg\'] = $msg;
            $_SESSION[\'token\'] = $token;
            header(\'Location: mobile_verify.php\');
        }
    }else{
        header(\'Location: index.php\');
        die();
    }

    $conn->close();
?>
  • 查询太多...如果您获取“活跃”用户,这些用户不能同时处于非活跃状态。
  • @LarsStegelitz 那你有什么建议?在第一个查询中,我不应该使用 \"where email_token = ? \"
  • 第一个查询已过时,因为您需要的所有信息都包含在第二个查询中。
  • @LarsStegelitz 那么这个怎么样。 \"SELECT email_token, email_status FROM users where email_token = ? LIMIT 1\"; ..... if(exist == 0){ $row = $result->fetch_array(MYSQLI_ASSOC); if($row[\'email_status\'] == \"active\"){ 然后执行此操作 }else{ 执行此操作 } }
  • 谢谢@LarsStegelitz,它可以完美地使用更少的代码和查询。

标签: php mysqli sql-update token


【解决方案1】:
  1. 通常,您不希望通过$_GET 请求在服务器端执行“写入”过程,但我想象您正在向用户发送电子邮件,而他们只是单击超链接,所以这是可以容忍的情况。
  2. 我不知道您的令牌在密码学上的安全性如何(UUID 是个好主意),但仅依赖一个数据点可能还不够。您可能希望在有效负载中包含第二个数据点,例如您发送到的 md5() 编码电子邮件,或令牌到期的表达式。这些辅助数据点不需要加密安全,但它应该消除意外的数据冲突或成功的暴力攻击。
  3. 我建议您的回复不是提供太多关于失败结果的细节。提供这些类型的线索将使黑客受益匪浅。

    很简单,执行一个更新查询,然后根据受影响的行数,重定向到需要的位置。确保在需要维护会话的每个页面的开头开始会话。

    未经测试的推荐:

    $token = $_GET['token'] ?? null;
    if ($token) {
        require('../private/autoload.php');
        $sql = "UPDATE users
                SET email_status='active'
                WHERE email_status='inactive'
                  AND email_token=? LIMIT 1";
        $stmt = $conn->prepare($sql);
        $stmt->bind_param("s", $token);
        $stmt->execute();
        if ($stmt->affected_rows) {
            $_SESSION['msg'] = "Email verified successfully, thank you.";
            $_SESSION['token'] = $token; // why store this in the session?
            header('Location: mobile_verify.php');
            exit();
        }
    }
    // missing or invalid submission
    header('Location: index.php');
    exit();
    

【讨论】:

  • 所以我明白你想说什么,你猜对了我使用的 GET 方法是因为用户正在点击发送给他的电子邮件以进行验证。另外我没有正确理解您的第 2 点,例如我应该发送电子邮件(加密)还是什么?对于您在代码中的问题,我将令牌存储在会话中,以便当用户转到 mobile_verify 时,该令牌用作特定用户的标识符。会话开始也在 autoload.php 中。
  • 首先,我的意思是让您将用户的电子邮件地址指定为 &amp;email=their_email@example.com 以及电子邮件中链接的查询字符串中已经存在的令牌。使用md5 将电子邮件地址编码为由数字和字母组成的字符串可以避免 url 编码问题(但肯定不是克服这一挑战的唯一方法)。其次,我不明白为什么有人被发送到此页面并成功激活令牌会对令牌有任何进一步的用途。如果您将其用作永久标识符,则可以。
  • 所以我应该在更新查询中使用令牌指定用户电子邮件?在成功的电子邮件验证后,用户需要验证那里的移动设备,所以我将他们重定向到带有令牌的移动页面,以便可以验证用户输入的手机号码,因为令牌是唯一的,因此只有一行具有相同的令牌和手机号码.
  • 啊啊啊。好的,好的,我明白了。 “手机号码验证”比“手机验证”更明确。
【解决方案2】:

建议是通过结合两者的方面来减少查询的数量。一个用户不能同时处于“活动”或“非活动”状态,因此不需要进行两次查询。

第一个查询已过时,因为所有信息都包含在第二个查询中。

(另请阅读初始帖子的cmets)

【讨论】:

  • 不,请在此处添加您的所有代码和建议,以便可以删除问题下的所有 cmets。这是问答而不是问答。理想情况下,页面上不应该有 cmets,因为问题包含所有必要的信息,所有答案都包含所有必要的建议。
  • 哦.. Sameer 自己提出解决方案,我没有提供代码,只提供建议.. 抱歉,如果我误解了你。
猜你喜欢
  • 1970-01-01
  • 2019-02-24
  • 2019-02-28
  • 1970-01-01
  • 1970-01-01
  • 2014-05-05
  • 1970-01-01
  • 2021-07-26
  • 2020-10-05
相关资源
最近更新 更多