我是数据库的新手,我编写了很多使用 MySQL 访问数据库的 PHP 代码。
我没有考虑到 SQL 注入(inject)攻击,所以我不得不重写所有 PHP 代码以使用 mysql 准备好的语句。
在观看了有关如何使用准备好的 SQL 语句的视频后,要执行一条 SQL 命令需要一大堆“准备好的”语句。我现有的代码到处都有很多不同的 SQL 语句,更改所有代码以打包和解包每个“准备好的”语句命令所需的所有准备工作将是一场噩梦。
是否可以使用某种包装器来防止将一行常规 SQL 转换为 6 或 7 行准备好的语句?
例如用来做这行SQL语句
SELECT * from users where userid=10
需要更多行准备好的 SQL 语句,特别是如果还有很多其他 SQL 语句,现在变得非常复杂。
是否有某种我可以调用的单行包装器,它接受模板 SQL 字符串和参数,它还执行命令并在不同类型的 MYSQL 语句的仅一行包装器中返回结果很棒,代码看起来不会那么困惑,也不会容易出错。
例如
$users=WrapAndExecute($db,"SELECT * from users where userid=?","s",$userid);
$data=WrapAndExecute($db,"UPDATE table SET username=?,city=?","ss",$name,$city);
$result=WrapAndExecute($db,"DELETE from table where id=?","s",$userid);
$result=WrapAndExecute($db,"INSERT into ? (name,address) VALUES(?,?)","ss","users",$name,$address);
上面的每一行都会创建一个准备好的语句模板,进行绑定(bind),执行它并返回常规 MYSQL 语句的结果。这将对现有代码产生最小的影响。
任何人都知道如何做到这一点,或者如果已经存在一些简单的 php 库或类来做到这一点,我可以导入并开始使用它吗?
谢谢
最佳答案
如果其中没有 PHP 变量,则无需将查询更改为准备好的语句。如果它只有常量表达式,它就不会受到 SQL 注入(inject)攻击。
$sql = "SELECT * from users where userid=10"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();
您无需更改包含 PHP 变量的查询,只要该变量的值是代码中指定的常量即可。如果它不从任何外部来源获取它的值(value),它就是安全的。
$uid = 10;
$sql = "SELECT * from users where userid=$uid"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();
您不需要更改包含 PHP 变量的查询,只要您可以过滤该值以保证它不会冒 SQL 注入(inject)的风险。一种快速简便的方法是将其转换为一个整数(如果它应该是一个整数)。
$uid = (int) $_GET['uid'];
$sql = "SELECT * from users where userid=$uid"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();
这会导致您使用“不受信任”的值,这些值可能源自用户输入、读取文件,甚至从数据库读取。在那些情况下,参数是保护您自己的最可靠方法。这很简单:
$sql = "SELECT * from users where userid=?"; // Safe!
// two lines instead of the one line query()
$stmt = $pdo->prepare($sql);
$stmt->execute([$_GET['uid']]);
$data = $stmt->fetchAll();
在某些情况下,您需要比通常使用的额外一行代码。
所以停止提示吧! ;-)
关于在 mysqli 中执行准备好的语句的评论。
它们绑定(bind)变量的方式比 PDO 更难使用。我不喜欢 http://php.net/manual/en/mysqli.prepare.php 中给出的示例
这是使用 mysqli 的更简单的方法:
$sql = "SELECT * from users where userid=?"; // Safe!
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('i', $_GET['uid']);
$stmt->execute();
$result = $stmt->get_result();
$data = $result->fetch_all();
我不喜欢他们在示例中使用 bind_result()
所做的事情,这令人困惑且没有必要。只需使用 get_result()
。因此,使用 mysqli,您需要比使用 PDO 多两行代码。
我已经为 mysqli 编写了查询包装器,它模拟了 PDO 的 execute()
函数的便利性。将数组映射到 bind_param()
的可变参数样式是一个 PITA。
请参阅我对 https://stackoverflow.com/a/15933696/20860 的回答中的解决方案或 https://stackoverflow.com/a/7383439/20860
关于php - 将常规 mysql 转换为准备好的语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43374839/