我是PHP和MySQL的新手,但我目前正在学习两者,以便创建一个管理我的RADIUS帐户的基本网站。 (我已经转而使用MySQL进行用户身份验证)
我制作了一个将用户值插入数据库的脚本,但是我需要这样做,就好像用户帐户已经存在一样,无法创建副本。
我正在使用我发现的一个教程来尝试创建它,它确实在一定程度上起作用。当我在没有重复帐户时添加用户时,我返回消息“Successful”但是当有重复用户时,返回的页面是空白的,我不确定我做错了什么。它可行,但很烦人。
我也很好奇是否有可能创建一个数字池(这些将是IP地址)然后拥有它以便在创建新用户时使用此池中的数字,然后从中删除池。通过这样做,我希望我可以自动为用户分配IP,而无需每次创建新用户时都有人手动添加它们。目前为了实现一种稍微不太理想的方法,我制作了另一个脚本,显示了我的表中的用户IP地址列表,这样就可以添加一个不在此列表中的IP。任何关于我可以学习如何做到这一点的建议将不胜感激,我不知道从哪里开始。
下面是我正在使用的php代码,以及表单的html代码。感谢您的帮助或建议。
<?php
define('DB_HOST', 'localhost');
define('DB_NAME', 'test');
define('DB_USER','root');
define('DB_PASSWORD','123');
$con=mysql_connect(DB_HOST,DB_USER,DB_PASSWORD) or die("Failed to connect to MySQL: " . mysql_error());
$db=mysql_select_db(DB_NAME,$con) or die("Failed to connect to MySQL: " . mysql_error());
function AuthAccount()
{
$username = $_POST['username'];
$value = $_POST['value'];
$query = "INSERT INTO radcheck(username, attribute, op, value) VALUES ('$username', 'Cleartext-Password', ':=', '$value')";
$data = mysql_query ($query)or die(mysql_error());
if($data)
{
echo "User added to authentication database";
}
}
function AddAccount()
{
if(!empty($_POST['username']))
{
$query = mysql_query("SELECT * FROM radcheck WHERE username = '$_POST[username]'") or die(mysql_error());
if(!$row = mysql_fetch_array($query) or die(mysql_error()))
{
AuthAccount();
}
else
{
echo "Username already registered";
}
}
}
if(isset($_POST['submit']))
{
AddAccount();
}
?>
注册页面:
<!DOCTYPE HTML>
<html>
<head>
<title>Sign-Up</title>
</head>
<body id="body-color">
<div id="Sign-Up">
<fieldset style="width:50%"><legend>Registration Form</legend>
<table border="0">
<form method="POST" action="SignUp.php">
<tr>
<td>Username</td><td> <input type="text" name="username"></td>
</tr>
<tr>
<td>Password</td><td> <input type="text" name="value"></td>
</tr>
<tr>
<td><input id="button" type="submit" name="submit" value="Sign-Up"></td>
</tr>
</form>
</table>
</fieldset>
</div>
</body>
</html>
答案 0 :(得分:1)
你的方法充满了问题:
您引入了种族危险,即同时尝试注册相同用户名的两个会话最终都会通过SELECT
测试,然后才能进入INSERT
。
如果您使用的是事务性存储引擎(例如Innodb),那么可以通过正确使用事务和locking reads来解决此问题,但它只是简单易行在数据库中强制使用唯一性约束,让MySQL完成剩下的工作:
ALTER TABLE radcheck ADD UNIQUE (username)
然后您可以直接转到INSERT
,如果用户名已经存在,则会引发错误,您可以据此处理。
在将它们内嵌到SQL中时,您没有转义字符串文字。这不仅是一个(严重的)security vulnerability,而且还会引入一个错误,如果有人发布包含'
字符的用户名或密码,您的代码就会中断。将文字值传递为parameters to prepared statements可以避免这些问题。
您正在使用古老的PHP扩展来访问MySQL。它自2006年以来一直没有更新,自2011年以来,它在PHP手册中明确表示不会使用它。从PHP v5.5开始,它已被弃用,它将在未来的版本中完全从PHP中删除。您应该切换到improved MySQL extension,PHP Data Objects或第三方抽象层。
您正在将明文密码存储在数据库中。这不仅会在您的数据库遭到入侵的情况下对您的应用程序的安全性造成相当大的风险,而且还会给您的用户带来更大的风险(因为他们可能会为其他帐户使用相同的密码)。为了他们的利益,你应该总是哈希每个密码 with salt ;您还应该小心保护其浏览器和服务器之间的密码,例如:使用HTTPS。
关于IP地址的分配,您的问题没有提供有关如何选择此类地址或使用它们的详细信息。通常会将这些问题留给现有的服务,例如DHCP,这只需要根据您的政策要求进行配置。
答案 1 :(得分:0)
我认为if(!$row = mysql_fetch_array($query) or die(mysql_error()))
不正确。
我会这样做:
class db {
public static function dbFactory($host, $dbase, $user, $pass) {
$pdo = new PDO("mysql:host=$host;dbname=$dbase", $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
return $pdo;
}
}
$db = db::dbFactory('localhost','mydbname','myusername','mypassword');
$db->beginTransaction();
try {
$stmt = $db->prepare("SELECT COUNT(*) as cnt FROM radcheck WHERE username = :uname");
$stmt->bindValue(':uname',$_POST[username]);
$stmt->execute();
$res = $stmt->fetch(PDO::FETCH_ASSOC);
if($res['cnt'] == 0) {
// go on ...
}
$db->commit();
} catch (Exception $e) {
$db->rollBack();
}