Viết một hàm (hoặc class) trong PHP/Laravel để kiểm tra một Request URL xem nó có khớp với các chuỗi pattern chứa dấu sao (wildcard) như '/orders/tracking/*' hay không.
Dưới đây là cách triển khai logic kiểm tra URL khớp với các chuỗi pattern có chứa ký tự đại diện (wildcard *) trong PHP/Laravel.
Laravel cung cấp sẵn một class rất mạnh mẽ tên là Str chứa hàm Str::is(), được thiết kế chính xác để giải quyết bài toán so khớp chuỗi (string matching) với wildcard.
**1.Cách 1: Sử dụng Str::is() của Laravel (Khuyên dùng)
*Sử dụng hàm có sẵn.
Nếu bạn đang code trong Laravel, tuyệt đối không nên viết lại hàm Regex thủ công vì Laravel đã bọc sẵn chức năng này một cách an toàn và tối ưu hiệu năng.
PHP
use Illuminate\Support\Str;
class RouteMatcher
{
/**
* Kiểm tra xem đường dẫn hiện tại có khớp với danh sách pattern cho phép không
*
* @param string $requestPath URL client đang truy cập (ví dụ: '/orders/tracking/123')
* @param array $allowedPatterns Danh sách các pattern (ví dụ: ['/orders/tracking/search', '/orders/tracking/*'])
* @return bool
*/
public static function isAllowed(string $requestPath, array $allowedPatterns): bool
{
// Duyệt qua từng pattern trong mảng
foreach ($allowedPatterns as $pattern) {
// Hàm Str::is() tự động xử lý ký tự '*' thành Regex hợp lệ
if (Str::is($pattern, $requestPath)) {
return true; // Khớp với một trong các pattern, cho phép đi qua
}
}
return false; // Không khớp pattern nào, chặn lại
}
}
// --- CÁCH SỬ DỤNG TRONG MIDDLEWARE ---
// Giả sử request hiện tại đang gọi tới: /orders/tracking/detail/123
$path = request()->path(); // hoặc request()->getRequestUri() tùy ngữ cảnh
// Nếu request()->path() không có dấu '/' ở đầu, hãy đảm bảo format đồng nhất:
$path = '/' . ltrim($path, '/');
$patterns = [
'/orders/tracking/search',
'/orders/tracking/*',
];
$isMatched = RouteMatcher::isAllowed($path, $patterns);
// Kết quả: true (vì khớp với '/orders/tracking/*')
**2.Cách 2: Viết hàm Regex thuần (Nếu không dùng Laravel)
*Pure PHP.
Nếu bạn đang code trong môi trường PHP thuần (hoặc muốn hiểu cơ chế thực sự bên dưới), bạn cần tự chuyển đổi dấu * thành Biểu thức chính quy (Regular Expression) .*.
PHP
class PurePhpRouteMatcher
{
public static function isAllowed(string $requestPath, array $allowedPatterns): bool
{
foreach ($allowedPatterns as $pattern) {
// Bước 1: Tránh lỗi nếu pattern chứa các ký tự đặc biệt của Regex (như ? . +)
$escapedPattern = preg_quote($pattern, '#');
// Bước 2: Chuyển đổi ký tự đại diện '*' (đã bị escape thành '\*') thành '.*'
// '.*' trong Regex nghĩa là: Bất kỳ ký tự nào, lặp lại 0 hoặc nhiều lần
$regex = str_replace('\*', '.*', $escapedPattern);
// Bước 3: Đóng gói thành một Regex hoàn chỉnh.
// Cờ ^ (bắt đầu) và $ (kết thúc) đảm bảo khớp toàn bộ chuỗi
$fullRegex = '#^' . $regex . '$#u';
// So khớp chuỗi request path với Regex
if (preg_match($fullRegex, $requestPath) === 1) {
return true;
}
}
return false;
}
}
// --- CÁCH SỬ DỤNG ---
$path = '/orders/tracking/search/advanced';
$patterns = ['/orders/tracking/*'];
$isMatched = PurePhpRouteMatcher::isAllowed($path, $patterns);
// Kết quả: true
Lưu ý quan trọng về trailing slash (dấu gạch chéo cuối):
Trong cả hai cách trên, pattern
/orders/tracking/*sẽ KHÔNG khớp với chuỗi/orders/tracking(thiếu phần đuôi). Nó chỉ khớp nếu URL là/orders/tracking/hoặc/orders/tracking/abc.Nếu bạn muốn cho phép cả route gốc và tất cả route con, bạn phải cấu hình mảng với 2 phần tử tách biệt:
['/orders/tracking', '/orders/tracking/*']
All Rights Reserved