LaravelのEloquentでLike検索するとき、検索キーワードをエスケープしないと、予期しない結果が返ることがあります。
// エスケープしないコードの例
$products = Product::where('name', 'like', '%'.$name.'%')->get();
productsテーブルには、「オレンジ100%」と「オレンジ100個分」が登録されています。
>>> Product::all();
=> Illuminate\Database\Eloquent\Collection {#4148
all: [
App\Product {#3901
id: 1,
name: "オレンジ100%",
},
App\Product {#3533
id: 2,
name: "オレンジ100個分",
},
],
}
キーワード「100%」で検索します。
>>> $name = '100%';
=> "100%"
キーワードをエスケープせずに検索すると、キーワードを含まないレコードもヒットします。
>>> Product::where('name', 'like', '%'.$name.'%')->get();
=> Illuminate\Database\Eloquent\Collection {#3218
all: [
App\Product {#4151
id: 1,
name: "オレンジ100%",
},
App\Product {#4006
id: 2,
name: "オレンジ100個分",
},
],
}
キーワードをエスケープする関数を作成します。
>>> function escape_like(string $value, string $char = '\\'): string
... {
... return str_replace(
... [$char, '%', '_'],
... [$char.$char, $char.'%', $char.'_'],
... $value
... );
... }
キーワードをエスケープして検索します。
>>> Product::where('name', 'like', '%'.escape_like($name).'%')->get();
=> Illuminate\Database\Eloquent\Collection {#4165
all: [
App\Product {#4170
id: 1,
name: "オレンジ100%",
},
],
}
正しい結果が得られました。