如何使用sqlsrv_prepare函数?SQL Server网站搜索防注入
手把手教你用sqlsrv_prepare实现安全的搜索功能
嘿,我懂你这种看着文档却摸不着头脑的感觉!别慌,结合你的搜索场景,我一步步把sqlsrv_prepare的用法讲透,保证你看完就能上手,还能彻底防SQL注入。
首先得搞明白,sqlsrv_prepare的核心就是把SQL结构和参数彻底分开——数据库会先把你的SQL模板(比如带占位符的查询语句)预编译好,再把参数塞进去执行,这样参数里的特殊字符(比如'、--这些注入常用的)就只会被当成普通文本,根本不会被解析成SQL指令,从根源上杜绝注入风险。
接下来直接上适配你场景的完整代码,每一步都给你标清楚:
第一步:先搞定数据库连接
// 替换成你的数据库配置 $serverName = "localhost"; // 或者你的SQL Server地址 $connectionOptions = [ "Database" => "你的数据库名", "Uid" => "数据库用户名", "PWD" => "数据库密码" ]; // 建立连接,失败就输出错误 $conn = sqlsrv_connect($serverName, $connectionOptions); if (!$conn) { die("数据库连接炸了:" . print_r(sqlsrv_errors(), true)); }
第二步:处理搜索参数
这里要注意,不要直接把用户输入的内容拼进SQL,我们把%加到参数值里,而不是SQL语句中:
// 获取POST过来的搜索关键词,先做基本的空值处理和去空格 $search = isset($_POST["search"]) ? trim($_POST["search"]) : ""; // 把通配符%和关键词拼接,用于LIKE查询 $searchParam = "%$search%";
第三步:预编译SQL语句(核心步骤!)
sqlsrv用?作为参数占位符,顺序一定要和后面的参数数组对应:
// 写SQL模板,用?代替要传入的参数 $sql = "SELECT * FROM 你的表名 WHERE 要搜索的字段名 LIKE ?"; // 定义参数数组,每个元素是一个子数组,指定参数值和类型 // SQLSRV_PARAM_IN表示这是输入参数(给数据库传值) $params = [ [$searchParam, SQLSRV_PARAM_IN] // 如果需要更严谨,可以指定数据类型,比如字符串类型: // [$searchParam, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING, SQLSRV_SQLTYPE_VARCHAR(255)] ]; // 执行预编译,得到语句对象 $stmt = sqlsrv_prepare($conn, $sql, $params); if (!$stmt) { die("预编译失败:" . print_r(sqlsrv_errors(), true)); }
第四步:执行预编译好的语句并处理结果
// 执行语句 if (sqlsrv_execute($stmt)) { // 循环读取结果,SQLSRV_FETCH_ASSOC表示返回关联数组(用字段名当键) while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { // 这里替换成你要输出的字段,比如: echo "ID: {$row['id']} | 标题: {$row['title']}<br>"; } } else { die("查询执行失败:" . print_r(sqlsrv_errors(), true)); }
第五步:收尾工作,释放资源
// 释放语句资源 sqlsrv_free_stmt($stmt); // 关闭数据库连接 sqlsrv_close($conn);
敲黑板划重点!这些坑千万别踩:
- 占位符只能用
?:sqlsrv不支持命名占位符(比如:search),参数数组的顺序必须和SQL里的?完全对应,错一个位置就会出问题。 %一定要加在参数里:绝对不能写成LIKE '%?%',这样数据库会把?当成字符串的一部分,参数绑定直接失效,等于白做了防注入。- 一定要检查错误:
sqlsrv_errors()能返回详细的错误信息,调试的时候别嫌麻烦,加进去能帮你快速定位问题。 - 参数类型可选但建议加:如果你的字段是固定类型(比如整数、日期),指定参数类型能避免类型转换导致的奇怪问题,让代码更健壮。
最后再补充一句,sqlsrv_prepare和sqlsrv_query的区别:如果只是执行一次查询,用sqlsrv_query也能实现参数绑定,但sqlsrv_prepare适合需要重复执行同一条SQL(比如批量插入)的场景,预编译一次后多次执行,效率更高。而你的搜索场景用它,核心目的就是安全防注入,完全没问题。
内容的提问来源于stack exchange,提问作者TakeDown
相关产品推荐
相关产品推荐

