如何只允许一个用户在 php 中编辑表单?
Posted
技术标签:
【中文标题】如何只允许一个用户在 php 中编辑表单?【英文标题】:How to allow only one user edit the form in php? 【发布时间】:2020-08-07 11:50:16 【问题描述】:我有一个如下所示的 php 代码,其中 用户名/密码 通过 db 验证,只允许一个用户登录(在下面 php 代码中的第 X 行)强>。
在 php 代码中,表 trace_users(user_name、open、write 是列)保持登录用户的轨迹。当任何用户登录时,open 列设置为 true,write 列的值为 1。如果用户注销,则 open 列设置为 false,write 列的值为 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 is currently editing the form. Want to take over ?
。
我想要实现的是,如果 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 代码中进行哪些更改,以便如果 userA 已登录并且 userB 也想登录并尝试接管表单 那么 userA 应该没有写入权限,并且 userB 应该被授予完全访问权限,即
用户A(open=true , write=0)
用户B(open=true, write=1)
注意:对于没有写入权限的用户,将不会显示保存按钮。
【问题讨论】:
我可能理解错了,但是按照你的说法,应该只是 UserA: open = true, write = false and UserB open = true, write = false?我错过了什么吗? 如果用户 A 已登录 (open=true, write=1) 并且用户 B 接管,则用户 B 应该是 open=true, write=1。接管用户 A 将是 (open=true, write=0) 我同意,那有什么问题呢?你想要 php 代码来执行更改吗?看来您已经知道该怎么做了,也许我理解错了? 我尝试了一些东西,但我不确定它是对还是错。如果用户 B 接管,则应为用户 A 授予只读访问权限。用户 A => open = true,write = 0 和 User B => open = true,write = 1。 我的 php 代码在打开的列中只允许一个真值(一次只能登录一个)。 【参考方案1】:我发现您的方法存在两个基本问题:
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”可能在他们的浏览器中加载了旧数据。但这是一个你没有要求解决的问题,所以无论如何它可能对你来说不是问题。
【讨论】:
【参考方案2】:这样的事情怎么样?
$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 块内回显"<script type='text/javascript'>if(confirm('$message')) else ;</script>";
吗?
我想知道您是否可以让我知道如何将 sql 查询集成到 if 块的花括号中。【参考方案3】:
不建议在大型数据集上使用,但单行选项是将更新替换为包含对用户名的引用的更新:
$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']);
这将对表中的每条记录:
在 1 处保留 open=1 在用户名为 targetUser 的情况下设置 open=1 保持 open=0,其中 is 为 0,用户名不是 targetUser 在用户名为 targetUser 的情况下设置 write=1 在用户名不是 targetUser 的情况下设置 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']);
【讨论】:
【参考方案4】:问题更多在于流程逻辑,而不是代码:
-
UserA 连接(调用 1,php 授予访问权限:打开 => 1,写入 => 1)
UserB 连接(调用 2,php 向 UserB 显示弹出窗口:open => 1)
UserB 必须决定接管(或不接管)(调用 3,php 授予 UserB 写入权限并撤销 UserA 的写入权限:UserA write => 0, UserB write=>1)
使用您的代码管理第 1 步和第 2 步。 当 UserB 决定接管时,步骤 2 的 php 代码已经结束(您提示了问题)。您必须编写专门的代码来获得 UserB 对问题的回答(这完全取决于您准备的 javascript)。
无论如何,您没有检查任何写访问权限,因此一旦用户 B 接管然后注销,用户 A 仍将处于打开连接状态但没有写访问权限。如果 UserB 再次连接,它将再次提示接管不存在的内容(UserA 写入权限已消失)。
【讨论】:
抱歉耽搁了。在你的Point 2中,你提到了open => 1。除非用户未登录,否则不会设置为 1。就是这样,我已经设计了流程。 没关系,无论第 2 步的打开状态是什么,即使他没有尝试连接。 (并且选择是接管或不连接)。没关系,他决定接管与否是在第 2 步和第 3 步之间。所以第 3 步负责这个选择。以上是关于如何只允许一个用户在 php 中编辑表单?的主要内容,如果未能解决你的问题,请参考以下文章