我在网站中创建了一个html表单,以便访问我的网站的用户可以注册,该表单具有以下输入;用户名,性别,电子邮件和密码。
我想知道如何在将表单数据插入具有用户ip地址的数据库中的多列中时,如何使用mysqli准备好的语句(以保护我的站点免受sql注入)。
下面是我根据从我那里学到的教程以及我在这里阅读的答案所写的代码(带有验证)。
PHP代码
<?php
// connect to db
include 'db.php';
// variables
$msg = $error = $error0 = $error1 = $error2 = "";
if($_SERVER["REQUEST_METHOD"] == "POST") {
// username validation
if (empty(trim($_POST["username"]))) {
$error= '<font color="#dc3545">Your username is required</font>';
} elseif (strlen(preg_replace('/[^a-zA-Z]/m', '', $_POST["username"])) < 3) {
$error= '<font color="#dc3545">Your username must have atleast 3 letters</font>';
} elseif (strlen(preg_replace('/[^a-zA-Z]/m', '', $_POST["username"])) > 15) {
$error= '<font color="#dc3545">Your username is too long</font>';
} elseif (!preg_match("/^[A-Za-z0-9_\.]+$/ ", $_POST["username"])) {
$error = '<font color="#dc3545">Your username must be in letters with either a number(0-9), underscore(_) or dot(.)</font>';
} else {
// prepare select statement
$check_uname = "SELECT id FROM users WHERE username = ?";
if($stmt = mysqli_prepare($db, $check_uname)) {
// Bind variables to the prepared statement as parameters
mysqli_stmt_bind_param($stmt, "s", $param_username);
// Set parameters
$param_username = trim($_POST["username"]);
// Attempt to execute the prepared statement
if(mysqli_stmt_execute($stmt)){
/* store result */
mysqli_stmt_store_result($stmt);
if(mysqli_stmt_num_rows($stmt) == 1){
$error = '<font color="#dc3545"><b>'.$_POST["username"].'</b> is already in use</font>';
} else{
$username = trim($_POST["username"]);
}
} else{
$error = '<font color="#dc3545">Oops! Something went wrong. Please try again later</font>';
}
}
// Close statement
mysqli_stmt_close($stmt);
}
// gender validation
if (empty($_POST['gender'])) {
$error0 = '<font color="#dc3545">Your gender is required</font>';
} else {
$gender = $_POST['gender'];
}
// email validation
if (empty(trim($_POST["email"]))) {
$error1 = '<font color="red">Your email address is required</font>';
} elseif (!filter_var($_POST["email"], FILTER_VALIDATE_EMAIL)) {
$error1 = '<font color="red">Your email address is invalid</font>';
} else {
// prepare select statement
$check_email = "SELECT * FROM users WHERE email = ?";
if($stmt = mysqli_prepare($db, $check_email)) {
// Bind variables to the prepared statement as parameters
mysqli_stmt_bind_param($stmt, "s", $param_email);
// Set parameters
$param_email = trim($_POST["email"]);
// Attempt to execute the prepared statement
if(mysqli_stmt_execute($stmt)){
/* store result */
mysqli_stmt_store_result($stmt);
if(mysqli_stmt_num_rows($stmt) == 1){
$error1 = '<font color="#dc3545"><b>'.$_POST["email"].'</b> is already in use</font>';
} else{
$email = trim($_POST["email"]);
}
} else{
$error1 = '<font color="#dc3545">Oops! Something went wrong. Please try again later</font>';
}
}
}
// password validation
if (empty(trim($_POST['password']))) {
$error2 = '<font color="#dc3545">Your password is required</font>';
} elseif (strlen(trim($_POST['password'])) < 6) {
$error2 = '<font color="#dc3545">Password must be at leats 6 characters</font>';
} elseif (strlen(trim($_POST['password'])) > 150) {
$error2 = '<font color="#dc3545">Your password is to long</font>';
} else {
$password = trim($_POST['password']);
}
// check errors before inserting into database
if (empty($error) && empty($error0) && empty($error1) && empty($error2)) {
// prepare insert statement
// user name, email, gender and password stored in table `users`
$insert = "INSERT INTO users(username, email, gender, password) VALUES(?, ?, ?, ?)";
// user name, email and gender stored in table `users_profile`, username will be set as default user 'display_name'
$insert = "INSERT INTO users_profile(username, gender, email) VALUES(?, ?, ?)";
// user name stored in table `users_lastlogin_dt` to save user last login date
$insert = "INSERT INTO users_lastlogin_dt(username) VALUES(?)";
// user name stored in table `users_lastlogin_ip` to save user last login ip address
$insert = "INSERT INTO users_lastlogin_ip(username) VALUES(?)";
// user name, signup date and time stored in table `users_signup_dt` to save user signup date and time
$insert = "INSERT INTO users_signup_dt(username, date_n_time) VALUES(?, NOW())";
// user name and signup ip address stored in table `users_signup_dt`
$insert = "INSERT INTO users_signup_ip(username, ip) VALUES(?, ?)";
// user name stored in table `users_verified`
$insert = "INSERT INTO users_verified(username) VALUES(?)";
// user name stored in table `users_mod_man_sec_ver_ser`
$insert = "INSERT INTO users_mod_man_sec_ver_ser(username) VALUES(?)";
if($stmt = mysqli_prepare($db, $insert)) {
// bind variables to the prepared statement as parameters
mysqli_stmt_bind_param($stmt, "ss", $param_username, $param_gender, $param_email, $param_password);
// set parameters
$param_username = $username; // user's name
$param_gender = $gender; // user's gender
$param_email = $email; // user's email
$param_password = password_hash($password, PASSWORD_DEFAULT); // creates a password hash
$ip = $_SERVER['REMOTE_ADDR']; // grab users ip address
// attempt to execute the prepared statement
if(mysqli_stmt_execute($stmt)){
$msg = '<div class="alert a_success alert-dismissable" id="alert"><a href="#" class="close" data-dismiss="alert" aria-label="close">×</a><b>Signup was successful</b></div>';
} else {
$msg = '<div class="a_danger alert-dismissable" id="alert"><a href="#" class="close" data-dismiss="alert" aria-label="close">×</a><b>Signup was unsuccessful, please try again</b></div>';
}
}
// close statement
mysqli_stmt_close($stmt);
}
// close connection
mysqli_close($db);
}
// echo success message or failed message
echo $msg;
?>
HTML代码:
<div class="container">
<br>
<div class="row">
<center><h3><b>Create a new account</b></h3></center><br>
<div class="form_box">
<form id="canabody" method="POST" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"])?>" enctype="multipart/form-data">
<div class="form-grou">
<b>Username</b>
<br>
<input class="form-control" id="uname" type="text" name="username" placeholder="3 - 15 characters" maxlength="15" value="<?php if(isset($username)) echo $username; ?>" autocomplete="off" required>
<?php echo $error; ?>
</div>
<div class="form-group">
<b>Gender</b>
<br>
<select class="form-control custom-select" name="gender" id="ugender" required>
<option></option>
<option value="male" <?php if(isset($gender) && $gender == 'male') echo 'selected'; ?>>Male</option>
<option value="female" <?php if(isset($gender) && $gender == 'female') echo 'selected'; ?>>Female</option>
</select>
<?php echo $error0; ?>
</div>
<div class="form-group">
<b>Email address</b>
<br>
<input class="form-control" id="usrem" type="email" name="email" value="<?php if(isset($email)) echo $email; ?>" placeholder="yourname@domain.com" required>
<?php echo $error1; ?>
</div>
<div class="form-group">
<b>Password</b>
<br>
<input class="form-control" id="usrpass" type="password" name="password" maxlength="150" value="<?php if(isset($password)) echo $password; ?>" placeholder="6 - 150 characters" required>
<?php echo $error2; ?>
</div>
<button id="ok_but0" class="btn btn-primary btn-block" type="submit" name="reg_submit">Create account</button>
</form>
</div>
</div>
</div>
</div>
我不断收到错误消息;
警告::mysqli_stmt_bind_param():类型定义字符串中的元素数量与第160行的C:\ xampp \ htdocs \ d_project \ signup.php中的绑定变量数量不匹配
“第160行:mysqli_stmt_bind_param($ stmt,” ss“,$ param_username,$ param_gender,$ param_email,$ param_password);”。
答案 0 :(得分:1)
您似乎对多个插入物的工作方式感到困惑。我将举例说明Patrick Q和我在说什么:
<?php
// set parameters
$param_username = $username; // user's name
$param_gender = $gender; // user's gender
$param_email = $email; // user's email
$param_password = password_hash($password, PASSWORD_DEFAULT); // creates a password hash
$ip = $_SERVER['REMOTE_ADDR']; // grab users ip address
//FIRST Insert
$insert = "INSERT INTO users(username, email, gender, password) VALUES(?, ?, ?, ?)";
$stmt = mysqli_prepare($db, $insert);
mysqli_stmt_bind_param($stmt, "ssss", $param_username, $param_gender, $param_email, $param_password);
if(mysqli_stmt_execute($stmt)) {
...
}
//SECOND Insert
$insert = "INSERT INTO users_signup_ip(username, ip) VALUES(?, ?)";
$stmt = mysqli_prepare($db, $insert);
mysqli_stmt_bind_param($stmt, "ss", $param_username, $ip);
if(mysqli_stmt_execute($stmt)) {
...
}
如何处理错误也变得更加复杂。如果您想要一次失败以中止所有插入操作,则可以阅读事务。或者,如果遇到错误,您可以停止。或者,您可以保留一个错误数组并推送到其中,如果该数组不为空,则将其全部列出。
对于初学者来说,这不是一件容易的事,但这是一个值得学习的好练习。由于Patrick Q还观察到对所需内容的更好理解,可能使您重新考虑存储数据的结构。