PHP防SQL注入学习
该示例在MySQL8.0 + PHP7.3 + ThinkPHP5下操作
前提条件:
1.配置文件config.php中默认全局过滤方法
// 默认全局过滤方法 用逗号分隔多个 'default_filter' => '',
2.创建test表

3.创建test控制器
<?php namespace app\index\controller; use think\Controller; use think\Db; class Test extends Controller { public function index(){ if(input('post.')){ $data = [ 'content' => input('post.content'), ]; $result = Db::table('test')->insert($data); if($result){ dump("add suc"); } } $list = Db::table('test')->select(); $this->assign('list',$list); return $this->fetch('index/test'); } }
4.创建test模板
{include file="index/head" /} <form role="form" action="{:url('Test/index')}" method="post"> <div class="form-group"> <label>内容</label> <textarea class="form-control" name="content" rows="3"></textarea> </div> <button type="submit" class="btn btn-default">提交</button> </form> {volist name="list" id="vo"} <p>{$vo.content}</p> {/volist} </body> </html>
页面效果:

学习开始
addslashes()函数,会对单引号、双引号、反斜杠进行转义过滤
默认情况下,PHP会对所有的 GET、POST 和 COOKIE 数据自动运行 addslashes(),如果对已转义过的字符串使用 addslashes(),会导致双层转义,所以需要借助get_magic_quotes_gpc()函数进行检测。
代码修改如下
public function index(){ if(get_magic_quotes_gpc()){ dump("open"); }else{ dump("close"); } if(input('post.')){ $data = [ 'content' => input('post.content'), ]; $result = Db::table('test')->insert($data); if($result){ dump("add suc"); } } $list = Db::table('test')->select(); $this->assign('list',$list); return $this->fetch('index/test'); }
页面效果如下

get_magic_quotes_gpc()未开启,所以需要addslashes()过滤传参
先看没有用addslashes()过滤的传参
依次在输入框输入
‘这是一条测试语句’
“这是一条测试语句”
'这是一条测试语句'
"这是一条测试语句"
\这是一条测试语句\
数据表数据如下

页面效果如下

接下来对传参过滤
$data = [
'content' => addslashes(input('post.content')),
];
重复上述传参,下面是addslashes()过滤后的效果
数据库数据展示

页面效果

htmlspecialchars() 函数 将字符 “<” (小于)和 “>” (大于)转换为 HTML 实体
先看没有用htmlspecialchars()
转义的传参效果
在输入框输入
<b>这是一条测试语句</b>
数据表数据如下

页面效果如下

现在使用htmlspecialchars()
转义
$data = [
'content' => htmlspecialchars(input('post.content')),
];
数据如下

页面效果如下

strip_tags() 函数 会剥去字符串中的 HTML 标签
同样先看没用strip_tags()
前的效果
输入框输入
<b>这是一条测试语句</b>
数据表如下

页面效果如下

使用strip_tags()
后的效果
$data = [
'content' => strip_tags(input('post.content')),
];
数据表如下

页面效果如下

nl2br() 函数 在字符串中的新行(\n)之前插入换行符
先看没用nl2br()
前的效果
输入框输入

数据表如下

页面效果如下

下面是使用nl2br()
后的效果
$data = [
'content' => nl2br(input('post.content')),
];
数据表数据

页面效果

addcslashes() 函数 在指定的字符前添加反斜杠
addcslashes()
与addslashes()
作用类似,却不相同,常用在查询数据表的情况下
先在输入框输入以下参数
这是一条测试参数
这是一条测试%参数
这是一条测试_参数
数据表

页面效果

现在对上述数据进行like查询,修改代码
$list = Db::table('test')->select(); $this->assign('list',$list); $content = '测试%'; $content = '%'.$content.'%'; $search = Db::table('test')->where(['content'=>['like',$content]])->select(); $this->assign('search',$search);
{volist name="list" id="vo"}
<p>{$vo.content}</p>
{/volist}
<p>--------------------磕碜的分割线-----------------------</p>
{volist name="search" id="vo"}
<p>{$vo.content}</p>
{/volist}
页面效果如下

本意是查找测试%的,结果却将数据表的数据全查询出来的。
//查询条件修改如下,效果依旧如上所示 $content = '%测试_%';
总之数据中存在下划线或百分号,查询数据就会出现问题
现在使用addcslashes()
重新查询
$content = '测试%'; $content = addcslashes($content,'%_'); $content = '%'.$content.'%';重新like查询
页面效果如下

———————————华丽的分割线————————————–
结合上面所学,创建防sql注入方法
/* * 防sql注入 */ function sql_filter($post) { // 判断magic_quotes_gpc是否为打开 if (!get_magic_quotes_gpc()) { // magic_quotes_gpc没有打开的情况对提交数据的过滤 $post = addslashes($post); } $post = addcslashes($post, '%_'); //%_过滤 $post = htmlspecialchars($post); // html标记转换 $post = nl2br($post); // 回车转换 $post = strip_tags($post); return $post; }
上述防注入方法仅供参考,还请贴合自身网站使用