数据库查询中对 like 的值进行转义

在laravel中,如果要进行数据库的like模糊查询,可以这么做:

$query->where('title','like' , "%".$keyword."%");

不过这种做法却有几个问题:

  1. 重复书写like
  2. $keyword可能包含%_,这两个特殊字符将能够把数据库中所有的记录都能查找出来。

Laravel China社区的做法是直接把%_去掉了。

为了避免这种情况,我们可以自定义一个函数将我们的字符进行转义。

function escape_like_str($str)
{
    $like_escape_char = '!';

    return str_replace([$like_escape_char, '%', '_'], [
        $like_escape_char.$like_escape_char,
        $like_escape_char.'%',
        $like_escape_char.'_',
    ], $str);
}

使用时像这样

$query->where('title','like' , "%".escape_like_str($keyword)."%");

或者参考这个trait

<?php
namespace App\Models\Traits;

trait LikeScope
{
    /**
     * @param   \Illuminate\Database\Eloquent\Builder $query
     * @param     $column
     * @param     $value
     * @param     $side
     * @param     $isNotLike
     * @param     $isAnd
     * @return    \Illuminate\Database\Eloquent\Builder
     */
    public function scopeLike($query, $column, $value, $side = 'both', $isNotLike = false, $isAnd = true)
    {
        $operator = $isNotLike ? 'not like' : 'like';

        $escape_like_str = function ($str) {
            $like_escape_char = '!';

            return str_replace([$like_escape_char, '%', '_'], [
                $like_escape_char.$like_escape_char,
                $like_escape_char.'%',
                $like_escape_char.'_',
            ], $str);
        };

        switch ($side) {
            case 'none':
                $value = $escape_like_str($value);
                break;
            case 'before':
            case 'left':
                $value = "%{$escape_like_str($value)}";
                break;
            case 'after':
            case 'right':
                $value = "{$escape_like_str($value)}%";
                break;
            case 'both':
            case 'all':
            default:
                $value = "%{$escape_like_str($value)}%";
                break;
        }

        return $isAnd ? $query->where($column, $operator, $value) : $query->orWhere($column, $operator, $value);
    }

    public function scopeOrLike($query, $column, $value, $side = 'both', $isNotLike = false)
    {
        return $query->like($column, $value, $side, $isNotLike, false);
    }

    public function scopeNotLike($query, $column, $value, $side = 'both', $isAnd = true)
    {
        return $query->like($column, $value, $side, true, $isAnd);
    }

    public function scopeOrNotLike($query, $column, $value, $side = 'both')
    {
        return $query->like($column, $value, $side, true, false);
    }
}

使用方法

<?php
use App\Models\Traits\LikeScope;
use Illuminate\Database\Eloquent\Model;

class MyModel extends Model
{
    use LikeScope;

    public function scopeSearch($query, $keyword)
    {
        return $query->like('title', $keyword);
    }
}

我的代码参考了codeigniter的代码实现,欢迎各位批评或提出建议。如果有更好的方法也请多多指教

本帖已被设为精华帖!
本帖由系统于 3年前 自动加精
leililei
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 2

function escape_like_str($str){
$like_escape_char = “//“;
return str_replace([$like_escape_char, ‘%’, ‘‘], [
$like_escape_char.$like_escape_char,
$like_escape_char.’%’,
$like_escape_char.’
‘,
], $str);
}
$like_escape_char 应该为 ‘//‘;否则关键字包含 % _ 就搜不到

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!