• 您好!欢迎来到金点子源码网!
  • 登录 注册

源码网_提供网站源码、discuz、wordpress主题与插件和站长教程等资源的下载服务

易优站内搜索特殊字符报错如何解决

在使用易优CMS(YouZhanCMS)进行站内搜索时,如果用户输入包含**特殊字符**(如:`+`、`-`、`*`、`%`、`'`、`"`、`(`、`)` 等),可能会导致SQL查询报错或返回异常结果。这是因为这些字符可能被误解析为SQL语法的一部分,从而引发SQL注入防护机制拦截或语法错误。以下是常见的解决方案:


image.png

一、问题根源分析

常见报错场景

  1. 单引号(')You have an error in your SQL syntax

  2. 双引号("):导致JSON解析错误

  3. 反斜杠(\):转义错误

  4. 百分号(%):SQL LIKE查询异常

  5. 尖括号(<>):XSS过滤冲突

  6. 特殊符号:&AMP;、#、+ 等URL编码问题

二、快速解决方案

方案1:修改易优核心文件(推荐)

<PRe class="ybc-pre-component ybc-pre-component_not-math">// 文件位置:application/common/model/Search.php // 修改 search 方法中的关键词处理 public function search($keyword){     // 原始代码可能有问题,修改为:          // 1. 过滤特殊字符但保留中文、英文、数字     $keyword = preg_replace('/[^\x{4e00}-\x{9fa5}a-zA-Z0-9\s]/u', ' ', $keyword);          // 2. 或者仅移除危险字符     $danger_chars = ["'", '"', '\\', '%', '_', ';', '=', '>', '<', '&', '#', '(', ')'];     $keyword = str_replace($danger_chars, ' ', $keyword);          // 3. 去除多余空格     $keyword = trim(preg_replace('/\s+/', ' ', $keyword));          // 4. 如果关键词为空,返回空结果     if(empty($keyword)){         return ['list' => [], 'total' => 0];     }          // 5. 安全转义(ThinkPHP的查询构造器已处理,但双重保障)     $keyword = addslashes(strip_tags($keyword));          // 6. 对LIKE查询的特殊字符处理     $keyword = str_replace(         ['%', '_'],         ['\%', '\_'],         $keyword     );          // 原有搜索逻辑... }

方案2:修改前端输入处理

// 在搜索框提交前过滤
function filterSearchKeyword(keyword){
    // 移除危险字符
    var danger = /['"\\%;&=<>()#]/g;
    keyword = keyword.replace(danger, '');
    
    // 保留中英文数字和常用标点
    keyword = keyword.replace(/[^\u4e00-\u9fa5a-zA-Z0-9\s,。!?、:;()《》]/g, '');
    
    // 限制长度
    if(keyword.length > 50) keyword = keyword.substr(0, 50);
    
    return keyword.trim();
}

// 表单提交时调用
$('#search-form').submit(function(e){
    var keyword = $('#search-input').val();
    $('#search-input').val(filterSearchKeyword(keyword));
});

三、多层防御方案

1. 修改控制器层(优先级最高)

// 文件:application/index/controller/Search.php
public function index(){
    $keyword = input('keyword/s', '', 'trim');
    
    // 方法1:严格过滤
    $keyword = $this->filterKeyword($keyword);
    
    // 方法2:URL解码后过滤
    $keyword = urldecode($keyword);
    $keyword = Htmlspecialchars($keyword, ENT_QUOTES, 'UTF-8');
    
    // 方法3:正则保留安全字符
    $keyword = preg_replace('/[^a-zA-Z0-9\x{4e00}-\x{9fa5}\-\_\s]/u', '', $keyword);
    
    // 传递给模型
    $result = model('app\common\model\Search')->search($keyword);
    
    return json($result);
}

// 关键词过滤方法
private function filterKeyword($str){
    if(empty($str)) return '';
    
    // 移除SQL注入风险字符
    $str = str_ireplace(
        ['select ', 'insert ', 'update ', 'delete ', 'drop ', 'union ', 'or ', 'and '],
        '',
        $str
    );
    
    // 转义特殊字符
    $str = addslashes($str);
    
    // 限制长度
    if(mb_strlen($str, 'utf-8') > 100){
        $str = mb_substr($str, 0, 100, 'utf-8');
    }
    
    return $str;
}

2. 修改模板搜索表单

<!-- 在搜索表单模板中增加防护 -->
<!-- 原位置:template/你的模板/search.htm -->
<form action="{:url('/search')}" method="get" onsubmit="return validateSearch()">
    <input type="text" name="keyword" id="keyword" 
           placeholder="请输入关键词" 
           maxlength="50"
           oninput="filterInput(this)">
    <button type="submit">搜索</button>
</form>

<script>
function filterInput(input){
    // 实时过滤
    input.value = input.value.replace(/[<>'"\\&;#]/g, '');
}

function validateSearch(){
    var keyword = document.getElementById('keyword').value;
    if(!keyword.trim()){
        alert('请输入搜索关键词');
        return false;
    }
    if(keyword.length > 50){
        alert('关键词过长');
        return false;
    }
    return true;
}
</script>

四、数据库查询层防护

修改查询构造器

// 扩展ThinkPHP查询类
// 创建:application/common/Query.php
namespace app\common;

use think\db\Query;

class SafeQuery extends Query
{
    /**
     * LIKE查询安全处理
     */
    public function whereLike($field, $value, $logic = 'AND')
    {
        // 转义LIKE特殊字符
        $value = $this->escapeLike($value);
        return parent::whereLike($field, $value, $logic);
    }
    
    /**
     * 转义LIKE特殊字符
     */
    protected function escapeLike($str)
    {
        if(is_string($str)){
            $str = str_replace(
                ['\\', '%', '_'],
                ['\\\\', '\%', '\_'],
                $str
            );
        }
        return $str;
    }
    
    /**
     * 安全条件查询
     */
    public function whereSafe($field, $value, $logic = 'AND')
    {
        // 过滤危险值
        if(is_string($value)){
            $value = $this->filterValue($value);
        }
        return $this->where($field, $value, $logic);
    }
    
    protected function filterValue($value)
    {
        // 移除SQL关键字
        $keywords = [
            'select', 'insert', 'update', 'delete',
            'drop', 'truncate', 'create', 'alter',
            'union', 'or ', 'and ', 'xor',
            ';', '--', '/*', '*/', '#'
        ];
        
        foreach($keywords as $keyword){
            $value = str_ireplace($keyword, '', $value);
        }
        
        return trim($value);
    }
}

五、全局解决方案

创建搜索中间件

// 创建:application/http/middleware/SearchFilter.php
namespace app\http\middleware;

class SearchFilter
{
    public function handle($request, \Closure $next)
    {
        // 只处理搜索请求
        if($request->isGet() && strpos($request->pathinfo(), 'search') !== false){
            $keyword = $request->param('keyword');
            if($keyword){
                // 安全过滤
                $safeKeyword = $this->safeFilter($keyword);
                $request->withParam(['keyword' => $safeKeyword]);
            }
        }
        
        return $next($request);
    }
    
    protected function safeFilter($str)
    {
        // 1. URL解码
        $str = urldecode($str);
        
        // 2. HTML实体转义
        $str = htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
        
        // 3. 移除危险字符
        $danger = [
            "'", '"', '\\', ';', '=', '<', '>',
            '(', ')', '&', '#', '%', '*', '+',
            '!', '?', '~', '`', '|', '^'
        ];
        $str = str_replace($danger, ' ', $str);
        
        // 4. 移除多余空格
        $str = trim(preg_replace('/\s+/', ' ', $str));
        
        // 5. 长度限制
        if(mb_strlen($str, 'utf-8') > 100){
            $str = mb_substr($str, 0, 100, 'utf-8');
        }
        
        return $str;
    }
}

// 注册中间件:config/middleware.php
return [
    // 搜索过滤中间件
    \app\http\middleware\SearchFilter::class
];

六、Nginx层防护

配置Nginx过滤规则

# 在server配置中添加
server {
    # 搜索URL特殊字符过滤
    if ($request_uri ~* "/search"){
        # 检查危险字符
        if ($arg_keyword ~* "([';\\\"%=<>\(\)])"){
            return 400;
        }
        
        # 限制关键词长度
        if ($arg_keyword ~ "^.{101,}$"){
            return 413;
        }
    }
    
    # 或者使用rewrite重写
    location ~* ^/search {
        # 对关键词进行URL重写
        if ($args ~* "(keyword=.*[<>'].*)"){
            rewrite ^ /search?keyword= break;
        }
        
        # 正常处理
        try_files $uri $uri/ /index.php?s=$uri&$args;
    }
}

七、错误处理增强

修改异常处理

// 文件:app.php
'exception_handle' => 'app\common\exception\Handler',

// 创建异常处理类
namespace app\common\exception;

class Handler extends \think\exception\Handle
{
    public function render($request, \Throwable $e)
    {
        // 数据库错误(通常是SQL注入导致)
        if($e instanceof \think\db\exception\DbException){
            // 记录日志
            \think\facade\Log::error('搜索异常: ' . $e->getMessage());
            
            // 对搜索请求返回友好错误
            if(strpos($request->url(), 'search') !== false){
                return json([
                    'code' => 0,
                    'msg' => '搜索关键词包含特殊字符,请重新输入',
                    'data' => [],
                    'total' => 0
                ]);
            }
        }
        
        return parent::render($request, $e);
    }
}

八、测试验证方案

1. 创建测试脚本

// test_search.php
$testKeywords = [
    "正常关键词",
    "测试'单引号",
    '测试"双引号',
    "测试\\反斜杠",
    "测试%百分号",
    "测试_下划线",
    "测试<尖括号>",
    "测试&符号",
    "测试;分号",
    "测试=等号",
    "测试(括号)",
    "测试#井号",
    "测试--注释",
    "测试/*注释*/",
    "测试 or 1=1",
    "测试' and '1'='1",
    "测试 union select",
    "测试<script>alert(1)</script>",
    "混合测试'\"\\%<>"
];

foreach($testKeywords as $keyword){
    $url = "http://你的域名/search?keyword=" . urlencode($keyword);
    $result = file_get_contents($url);
    
    if(strpos($result, 'SQL syntax') !== false){
        echo "❌ 失败: " . $keyword . "\n";
    } else {
        echo "✅ 通过: " . $keyword . "\n";
    }
}

2. 压力测试

# 使用ab测试
ab -n 1000 -c 10 "http://域名/search?keyword=测试'特殊字符"

# 使用siege测试
siege -c 100 -r 10 "http://域名/search?keyword=测试<script>alert(1)</script>"

九、完整修复方案(推荐)

步骤1:创建全局过滤函数

// 文件:application/common.php
/**
 * 安全过滤搜索关键词
 */
function safe_search_keyword($keyword){
    if(empty($keyword)) return '';
    
    // 1. URL解码
    $keyword = urldecode($keyword);
    
    // 2. 基础过滤
    $keyword = strip_tags($keyword);
    $keyword = htmlspecialchars($keyword, ENT_QUOTES, 'UTF-8');
    
    // 3. 移除SQL危险字符
    $keyword = str_replace(
        ["'", '"', '\\', ';', '=', '--', '/*', '*/', '#'],
        '',
        $keyword
    );
    
    // 4. 移除SQL关键字
    $sql_keywords = [
        '/\bselect\b/i', '/\binsert\b/i', '/\bupdate\b/i', '/\bdelete\b/i',
        '/\bdrop\b/i', '/\btruncate\b/i', '/\bcreate\b/i', '/\balter\b/i',
        '/\bunion\b/i', '/\bor\b/i', '/\band\b/i'
    ];
    $keyword = preg_replace($sql_keywords, '', $keyword);
    
    // 5. 对LIKE查询转义
    $keyword = str_replace(['%', '_'], ['\%', '\_'], $keyword);
    
    // 6. 长度限制
    if(mb_strlen($keyword, 'utf-8') > 100){
        $keyword = mb_substr($keyword, 0, 100, 'utf-8');
    }
    
    return trim($keyword);
}

步骤2:修改搜索控制器

// 所有搜索相关控制器添加
public function search(){
    $keyword = input('keyword/s', '');
    
    // 使用全局过滤函数
    $safeKeyword = safe_search_keyword($keyword);
    
    if(empty($safeKeyword)){
        return $this->error('请输入有效的搜索关键词');
    }
    
    // 记录原始关键词(用于显示)
    $this->assign('original_keyword', $keyword);
    
    // 使用安全关键词搜索
    $result = model('app\common\model\Search')->search($safeKeyword);
    
    return $this->fetch('search', $result);
}

步骤3:修改前端显示

<!-- 显示时使用原始关键词,搜索时使用过滤后关键词 -->
<script>
// 显示原始关键词
var originalKeyword = "{$original_keyword|raw}";
$('.search-result-title').text('搜索结果:' + originalKeyword);

// 搜索时过滤
$('#search-btn').click(function(){
    var keyword = $('#keyword').val();
    var safeKeyword = keyword.replace(/[<>'"\\%;&=#()]/g, '');
    
    if(safeKeyword.length < 1){
        alert('请输入有效关键词');
        return false;
    }
    
    location.href = '/search?keyword=' + encodeURIComponent(safeKeyword);
});
</script>

十、预防措施

  1. 定期更新

    • 保持易优CMS最新版本

    • 关注官方安全更新

  2. 监控日志

    # 监控搜索异常
    tail -f runtime/log/*.log | grep -i "sql.*error\|exception"
    
    # 监控恶意搜索
    awk '/search/ && /['\''";<>]/' access.log
  3. WAF防护

    • 配置Web应用防火墙规则

    • 设置SQL注入防护

    • 启用XSS防护

  4. 数据备份

    • 定期备份数据库

    • 备份修改的文件

紧急修复命令

# 如果问题紧急,可先临时屏蔽特殊字符搜索
cd /网站根目录
sed -i "s/\$keyword = input('keyword'/\/\/ 临时修复:禁止特殊字符\n        \$keyword = input('keyword'/g" application/index/controller/Search.php
echo "修复完成,请刷新缓存"

通过上述方案,可彻底解决易优站内搜索特殊字符报错问题。推荐使用全局过滤函数方案,既能保证安全性,又能提供良好的用户体验。

本文链接:http://www.7ov.cn/xinwendongtai/2119.html

版权声明:站内所有文章皆来自网络转载,只供模板演示使用,并无任何其它意义!

上一篇: 易优cdn阅读量不变的缓存规则

下一篇:没有了

联系客服
网站客服 业务合作 在线客服QQ
294169012
微信号
微信号
微信号
返回顶部