如何在 PHP 中仅允许一个用户编辑表单?

4
我有一段php代码如下所示,其中通过db验证用户名/密码,并且只允许一个用户登录(在下面的php代码中的X行)
在php代码中,表格trace_usersuser_nameopenwrite是列)跟踪已登录的用户。当任何用户登录时,列open设置为true,并在列write上设置值为1。如果用户退出登录,则在write列上将open列设置为false,并将值设置为0已登录用户 => open = true, write = 1
当用户退出登录时 => open = false, write = 0 php代码:
if ($user_from_db && password_verify($password, $user_from_db->user_pass)) {

    $sql = "SELECT * FROM trace_users where open='true'";
    if($result1 = mysqli_query($connect, $sql)){
        if(mysqli_num_rows($result1) > 0){   // Line X
            while($row = mysqli_fetch_array($result1)){
                if($row['open'] == "true") {
                        if(!isset($_SESSION['admin'])) {
                            $message = "user " . $row['user_name'] . " is currently editing the form. Want to take over ?";
                            echo "<script type='text/javascript'>if(confirm('$message')) {   } else {  };</script>";   // Line A                        
                            }
                    break;
                }
            }
        } else{
            $_SESSION['admin'] = true;
            $_SESSION['user_name'] = $username;
            $open="true";
            $write="1";
            $stmt= $connect->prepare("UPDATE trace_users SET open=?, write=? WHERE user_name=?");
            $stmt->bind_param('sss', $open, $write, $_SESSION['user_name']);
            $stmt->execute();
        }
    }

} else {
    echo "Invalid Username or Password";
}

在A行,如果userA已登录并且另一个用户(比如userB)尝试登录,则会显示userA正在编辑表格。要接管吗?

我想要实现的是,如果userB在弹出框中点击“确定”接管了表单,则userA应该进入只读模式(撤销写访问权限),而userB应该拥有完全访问权限(写)。

userA => open = true, write = 0
userB => open = true, write = 1

这是我尝试过的内容:

在A行之后,我考虑添加这些代码,以便试图接管的用户能够登录。

$_SESSION['admin'] = true;
$_SESSION['user_name'] = $username;
$open="true";
$write="1";
$stmt= $connect->prepare("UPDATE trace_users SET open=?, write=? WHERE user_name=?");
$stmt->bind_param('sss', $open, $write, $_SESSION['user_name']);
$stmt->execute();
问题陈述:

我想知道在上面的php代码中应该做哪些更改,以便如果用户A已经登录,而用户B也想登录并尝试接管表单,那么用户A就没有写入权限,而用户B则应该获得完全访问权限,即:

用户A (open=true, write=0)

用户B (open=true, write=1)

注意:若要禁止写入,保存按钮将不会出现。


我可能误解了,但是根据你的意思,应该只是UserA:open = true,write = false和UserB open = true,write = false吗?我有什么遗漏吗? - LuisE
我尝试了一些东西,但不确定它是否正确。如果用户B接管,则应该给予用户A只读访问权限。用户A => 打开 = true,写入 = 0,用户B => 打开 = true,写入 = 1。 - user1950349
我的 PHP 代码只允许在 open 列中有一个真值(一次只能登录一个帐户)。 - user1950349
当你说“对于没有写入权限的用户,保存按钮将不会出现。”时,实际上当UserA首次登录时,保存按钮会出现,然后当UserB接管时,保存按钮会出现给UserB,但是你需要在客户端做一些事情,以便在UserB接管后不久隐藏UserA的保存按钮。那么你的客户端语言是什么,你打算如何做到这一点?如果你使用JavaScript和JQuery,可以轻松地在不重新加载页面的情况下完成它。 - Gimme the 411
@Gimmethe411 这是个好问题。如果您查看X行,我的代码只允许一个用户登录。我想我需要在那里做一些更改。 - user1950349
显示剩余4条评论
4个回答

0
问题更多地在于流程逻辑,而不是代码本身:
  1. UserA连接(调用1,php授予访问权限:open => 1,write => 1)
  2. UserB连接(调用2,php向UserB显示弹出窗口:open => 1)
  3. UserB必须决定接管还是不接管(调用3,php授予UserB写入权限并撤销UserA的写入权限:UserA write => 0,UserB write => 1)

使用您的代码,您正在管理步骤1和2。 当UserB决定接管时,步骤2的php代码已经完成(您提示了问题)。 您必须编写专用代码以获取UserB对问题的答案(这完全取决于您准备的javascript)。

无论如何,您都没有检查任何写入权限,因此一旦UserB接管并注销,UserA仍将保持打开状态,但没有写入权限。 如果UserB再次连接,它将再次提示接管不存在的内容(UserA写入权限已消失)。


抱歉耽搁了。在您的点2中,您提到了open => 1。除非用户未登录,否则不会将其设置为1。这是我设计流程的方式。 - user1950349
不用在意,在第二步无论是什么开放状态,即使他没有连接也会尝试。(而且选择是接管或不连接)。不用在意,在第二步和第三步之间,他决定接管还是不接管。所以第三步就负责这个选择。 - Tuckbros

0

我看到你的方法存在两个基本问题:

  • trace_users.write 列可能会意外地为多个用户设置为 1,除非在更新之前非常小心地锁定表。这不是追踪“活跃”编辑者的好方法。

  • 你的 line "A" 可能会显示一些 HTML,但在用户确认是/否之前,它不会被执行。该步骤必须在其他地方完成。

更好的方法是有一个单一的规范记录(可能在另一个表中)来跟踪当前管理员,你的代码可以随时检查(或更新)该记录。每当用户选择进行更改时,PHP 都会首先检查他们是否是活动编辑,如果是,则提交更新,否则拒绝更新。

以下是你需要的一些服务器端函数的伪代码:

// When an update is requested:
if ( user is logged in and is the current admin ) {
    commit the change;
} else {
    Display "sorry" message to user
}

// -----------

// When user "X" logs in:
if ( another user is currently the active admin ) {
    Display message: "User Y is currently the admin. Take over?"
} else {
    Log in user "X" and set user "X" to current admin
}

// -----------

// When user "X" asks to take over as admin:
log in user "X"
set user "X" to current admin

我唯一能看到的缺陷是,如果用户“A”已登录并正在编辑并保存更改,那么用户“B”在他们的浏览器中可能会加载旧数据。但这不是您要解决的问题,所以对您来说可能不是问题。

0

这样怎么样?

$username = $_SESSION['user_name'];
$open="true";
$write="1";
$stmt=$connect->prepare("UPDATE trace_users SET write=0 WHERE write=1"); // revoke write access of all users
$stmt=$connect->prepare("UPDATE trace_users SET open=:open, write=:write WHERE user_name=:username");
$stmt->bind_param('sss', $open, $write, $username);
$stmt->execute();

这将撤销所有用户的写入访问权限,然后仅为最近请求写入访问权限的用户设置写入访问权限。

您需要确保客户端已更新其写入访问权限的撤销,以便在必要时隐藏保存按钮。


抱歉回复晚了。我在想这段代码将放在哪里?它会放在if块内部的echo "<script type='text/javascript'>if(confirm('$message')) { } else { };</script>";吗? - user1950349
我想知道如何将SQL查询集成到if块的花括号中,请告诉我。 - user1950349

0

虽然不建议在大数据集上使用,但是一个适合您的单行选项是将您的更新替换为一个包含对用户名的引用的更新:

$stmt= $connect->prepare("UPDATE trace_users SET open=IF(open=1 OR user_name=?,1,0), write=IF(user_name=?,1,0)");
$stmt->bind_param('sss', $_SESSION['user_name'], $_SESSION['user_name']);

对于表中的每条记录,将执行以下操作:

  • 如果open=1,则保持不变
  • 如果username是目标用户,则设置open=1
  • 如果open=0且username不是目标用户,则保持不变
  • 如果username是目标用户,则设置write=1
  • 如果username不是目标用户,则设置write=0

一次性完成所有操作。


对于大型数据集,请创建一个单独的表进行跟踪。使用唯一或主键可以执行其他智能操作,以确保仅更新一条记录,然后验证“如果记录已更新(即rowCount() > 0),则我得到了标志,否则是其他人得到了它”。只有当您更熟悉MySQL时才考虑这一点。
警告:“Open”和“Write”都是关键字/保留字,你的SQL可能不具备可移植性。要么用反引号括起来,要么在前面加上类似userOpen、userWrite的前缀。我在下面的示例中添加了反引号。在这里阅读更多信息:https://dev.mysql.com/doc/refman/8.0/en/keywords.html
$stmt= $connect->prepare("UPDATE trace_users SET `open`=IF(`open`=1 OR user_name=?,1,0), `write`=IF(user_name=?,1,0)");
$stmt->bind_param('sss', $_SESSION['user_name'], $_SESSION['user_name']);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接