这是我的代码。
function login($username,$password){
global $db;
$sql = "SELECT * FROM users133 WHERE username=:username";
$stmt = $db->prepare($sql);
$stmt->execute(array(':username' => $username));
if ($stmt->rowCount() > 0){
$result = $stmt->fetchAll();
$hash = $result[0]['password'];
if (password_verify($password, $hash)) {
$_SESSION['loggedIn'] = $result[0]['id'];
header("location: ?page=profile"); /*<----AFTER LOGING IN YOU GET TO THIS PAGE*/
}else{
header("location: ?page=loginfailed");
}
}
else{
header("location: ?page=loginfailed");
}
}
是的,我知道该帖子是重复的,但是还有其他问题我需要问!!今天我花了大约6个小时来阅读如何做准备好的陈述。我读到有关$ stmt-> bindParam命令的信息,该命令使数据库检查输入的值是否为int,string等(以防用户使用检阅元素选项或以表格形式放置恶意代码)。 SELECT准备好的语句是否有必要?我打算从此登录功能复制代码,并在我的网站的其他地方使用它。这就是为什么我需要询问它是否以目前的方式是100%安全的。
答案 0 :(得分:4)
是的,您正在使用带有参数的预备语句。那是正确的事情。在大多数情况下,参数是编写安全SQL语句的最佳方法。在极少数情况下它们无济于事(请参阅我对how safe are PDO prepared statements的回答)
根据我的代码编写方式,我可以建议一些小的更改。
$sql = "SELECT id, password FROM users133 WHERE username=:username";
避免使用SELECT *
,请始终明确拼写您的列。见
$stmt = $db->prepare($sql);
$stmt->execute(['username' => $username]);
如果启用了PDO异常,则可以,因为任何SQL错误都会中断代码并引发异常。但是,如果未启用例外,则应始终检查prepare()
和execute()
的返回值。参见http://php.net/manual/en/pdo.error-handling.php和http://php.net/manual/en/pdo.errorinfo.php
array()
的语法来自旧的PHP版本,并且自PHP 5.4起,您可以在方括号中使用较短的语法。
您不需要在PDO参数的密钥中使用:
。仅在SQL字符串中。在旧版本的PDO中,两个地方都需要:
,但现在不再需要。
while (row = $stmt->fetch()) {
$hash = $row['password'];
if (password_verify($password, $hash)) {
$_SESSION['loggedIn'] = $row['id'];
header("location: ?page=profile");
}else{
header("location: ?page=loginfailed");
}
}
header("location: ?page=loginfailed");
以上内容避免了调用rowCount()
。如果没有行,则while()
自然会不做任何循环就结束,然后进入最后的header()
调用。
我宁愿避免调用rowCount()
,因为记住它何时有效以及何时无效都令人困惑。在客户端从MySQL服务器获取所有行之前,rowCount()
将返回0。有时,执行查询会隐式地将所有行提取到客户端内存中,然后调用fetch()
只是对其进行迭代。这称为缓冲查询。但是,如果您的结果将有太多行要缓冲,则非缓冲查询很有用。因此,并不总是清楚rowCount()
何时会返回准确的计数。