【发布时间】:2011-12-25 01:27:31
【问题描述】:
我一直都是做mysql_connect、mysql_pconnect的简单连接:
$db = mysql_pconnect('*host*', '*user*', '*pass*');
if (!$db) {
echo("<strong>Error:</strong> Could not connect to the database!");
exit;
}
mysql_select_db('*database*');
在使用此功能时,我总是使用简单的方法在进行查询之前转义任何数据,无论是INSERT、SELECT、UPDATE 还是DELETE,使用mysql_real_escape_string
$name = $_POST['name'];
$name = mysql_real_escape_string($name);
$sql = mysql_query("SELECT * FROM `users` WHERE (`name` = '$name')") or die(mysql_error());
现在我明白这在一定程度上是安全的!
它逃脱了危险的字符;但是,它仍然容易受到其他可能包含安全字符的攻击,但可能对显示数据或在某些情况下恶意修改或删除数据有害。
所以,我搜索了一下,发现了 PDO、MySQLi 和准备好的语句。是的,我可能迟到了,但我已经阅读了很多很多教程(tizag、W3C、博客、谷歌搜索),但没有一个人提到这些。原因似乎很奇怪,因为仅仅转义用户输入确实不安全,至少可以说不是好的做法。是的,我知道您可以使用 Regex 来解决它,但我很确定这还不够吗?
据我了解,当变量由用户输入给出时,使用 PDO/prepared 语句是一种更安全的方式来存储和检索数据库中的数据。唯一的麻烦是,切换(尤其是在我非常坚持以前的编码方式/习惯之后)有点困难。
现在我知道要使用 PDO 连接到我的数据库,我会使用
$hostname = '*host*';
$username = '*user*';
$password = '*pass*';
$database = '*database*'
$dbh = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);
if ($dbh) {
echo 'Connected to database';
} else {
echo 'Could not connect to database';
}
现在,函数名称不同了,所以我的 mysql_query、mysql_fetch_array、mysql_num_rows 等不再起作用。所以我不得不阅读/记住很多新的,但这就是我感到困惑的地方。
如果我想从注册/注册表单中插入数据,我将如何执行此操作,但主要是如何安全地执行此操作?我认为这是准备好的语句出现的地方,但是通过使用它们是否消除了使用 mysql_real_escape_string 之类的东西的需要?我知道mysql_real_escape_string 要求您通过mysql_connect/mysql_pconnect 连接到数据库,所以现在我们都没有使用,这个函数不会产生错误吗?
我也看到了处理 PDO 方法的不同方法,例如,我看到 :variable 和 ? 是我认为的占位符(如果有误,请见谅)。
但我认为这大致是从数据库中获取用户应该做什么的想法
$user_id = $_GET['id']; // For example from a URL query string
$stmt = $dbh->prepare("SELECT * FROM `users` WHERE `id` = :user_id");
$stmt->bindParam(':user_id', $user_id, PDO::PARAM_INT);
但是我遇到了一些问题,如果变量不是数字而是文本字符串,如果我没记错的话,你必须在 PDO:PARAM_STR 之后给出一个长度。但是,如果您不确定用户输入数据给出的值,如何给出一个设定的长度,它每次都会变化?无论哪种方式,据我所知显示您然后执行的数据
$stmt->execute();
$result = $stmt->fetchAll();
// Either
foreach($result as $row) {
echo $row['user_id'].'<br />';
echo $row['user_name'].'<br />';
echo $row['user_email'];
}
// Or
foreach($result as $row) {
$user_id = $row['user_id'];
$user_name = $row['user_name'];
$user_email = $row['user_email'];
}
echo("".$user_id."<br />".$user_name."<br />".$user_email."");
现在,这一切安全吗?
如果我是对的,例如插入数据是否相同:
$username = $_POST['username'];
$email = $_POST['email'];
$stmt = $dbh->prepare("INSERT INTO `users` (username, email)
VALUES (:username, :email)");
$stmt->bindParam(':username, $username, PDO::PARAM_STR, ?_LENGTH_?);
$stmt->bindParam(':email, $email, PDO::PARAM_STR, ?_LENGTH_?);
$stmt->execute();
这样行得通吗,那也安全吗?如果它是正确的,我会为?_LENGTH_? 赋予什么价值?我完全搞错了吗?
更新
到目前为止,我收到的回复非常有帮助,非常感谢你们!每个人都有一个+1,因为我睁开了眼睛看到了一些不同的东西。很难选择最佳答案,但我认为上校 Shrapnel 应得的,因为几乎涵盖了所有内容,甚至使用我不知道的自定义库进入其他数组!
但是感谢你们所有人:)
【问题讨论】:
-
可能是“用户名”和“电子邮件”字段的长度?例如。如果用户名是 varchar(32),那么长度参数应该是 32。
标签: php mysql database pdo prepared-statement