Laravel - tuyến regex khớp với mọi thứ nhưng không chính xác một hoặc nhiều từ


8

Tôi làm một lộ trình như

Route::get('/{url1}', function ($url1) {
    return ' url1: '.$url1;
})
->where('url1', '^(?!(string1|string2)$)');

và truy cập url như:
- domain/abc không tìm thấy => không chính xác ??
- domain/string1không tìm thấy => đúng

và hơn thế nữa, khi tôi làm với

Route::get('/{url1}/{url2}', function ($url1) {
    return ' url1: '.$url1;
})
->where('url1', '^(?!(string1|string2)$)');

và truy cập url như:
- domain/abc/abc không tìm thấy => không chính xác ???
- domain/string1/abckhông tìm thấy => đúng

Cách khắc phục


Trong đó chuỗi sẽ là tĩnh hay động?
Mitesh Rathod

@MiteshRathod chuỗi1 và chuỗi2 là từ đặc biệt (đó là tĩnh)
DeLe

chỉ 2 chuỗi này không chấp nhận trong url, đúng không?
Mitesh Rathod

@MiteshRathod có, chuỗi1 hoặc chuỗi2 sẽ không được chấp nhận trong url
DeLe

Vui lòng thêm biểu thức chính xác của bạn.
revo

Câu trả lời:


3

Vui lòng thử với kịch bản thứ 1 này:

Route::get('/{url1}', function ($url1) {
    return ' url1: '.$url1;
})->where('url1', '^!(string1|string2)$');

cho kịch bản thứ 2:

Route::get('/{url1}/{url2}', function ($url1, $url2) {
    return ' url1: '.$url1 . ' url2: '.$url2;
})->where('url1', '^!(string1|string2)$');

tôi hy vọng sự giúp đỡ này :)


thankiu nhưng, tôi chỉ thử thứ 1 với domain/abcnhưng nó không được tìm thấy?
DeLe

3

Thử cái này

 Route::get('{url1}', function ($url1) {
    return ' url1: '.$url1;
})->where('url1','^(?!string1$|string2$)([a-zA-Z0-9-]+)');

Cách ô uế để đạt được điều này

Route::get('{url1}/{url2?}', function ($url1,$url2 = null) {
        if ($url2 == "string1" || $url2 == "string2" || $url1 == "string1" || $url1 == "string2") {
            return "false";
        } else {
            return "true";
        }
});

Một cách nữa tôi đã thử bằng cách sử dụng RouteServiceProvider.php

Thay đổi của bạn boot()như thế này.

public function boot()
    {
        //
        Route::pattern('url1', '^(?!string1$|string2$)([a-zA-Z0-9-]+)');
        Route::pattern('url2', '^(?!string1$|string2$)([a-zA-Z0-9-]+)');
        parent::boot();
    }

thankiu, nhưng nó không hoạt động tốt Tôi chỉ thử domain/string1=> nó vẫn được tìm thấy
DeLe

@DeLe lạ Tôi đã thử cùng một mã, nhưng nó s excluding 127.0.0.1:8000/domain/opes2 , 127.0.0.1:8000/domain/opes1 `và làm việc chohttp://127.0.0.1:8000/domain/abc
Prashant Deshmukh .....

xin lỗi vì domain, domainnhư http://127.0.0.1:8000và bạn nên cố gắng 127.0.0.1:8000/string1, ...
Dele

@DeLe Cập nhật, kiểm tra ngay.
Prashant Deshmukh .....

1
@DeLe Kiểm tra câu trả lời cập nhật bằng cách sử dụng RouteServiceProvider.
Prashant Deshmukh .....

3

Sau khi kiểm tra tôi nghĩ không thể đạt được chính xác những gì bạn muốn. Có vẻ như khi bạn muốn loại trừ string1string2bạn cần phải đồng ý rằng các chuỗi bắt đầu bằng string1string2sẽ bị loại trừ (ví dụ như vậy string1aaa).

Khi sử dụng các tuyến đường như vậy:

Route::get('/{url1}', function ($url1) {
    return ' url1: '.$url1;
})->where('url1', '(?!string1|string2)[^\/]+');


Route::get('/{url1}/{url2}', function ($url1, $url2) {
    return ' url1: '.$url1. ' # '.$url2;
})->where('url1', '(?!string1|string2)[^\/]+');

kết quả sẽ là:

domain/abc - found, correct
domain/string1 - not found, correct
domain/abc/abc - found, correct
domain/string1/abc - not found, correct
domain/string1aaa - not found, I believe you need to accept this
domain/string1aaa/abc - not found, I believe you need to accept this

Tôi tin rằng giới hạn như vậy đến từ Laravel chứ không phải từ regex. Nếu bạn cũng cần chấp nhận các tham số bắt đầu string1string2tôi tin rằng bạn cần thực hiện theo cách thủ công như vậy:

Route::get('/{url1}', function ($url1) {
    if (!preg_match('#^(?!string1$|string2$)[^\/]*$#', $url1)) {
        abort(404);
    }

    return ' url1: '.$url1;
});


Route::get('/{url1}/{url2}', function ($url1, $url2) {
    if (!preg_match('#^(?!string1$|string2$)[^\/]*$#', $url1)) {
        abort(404);
    }

    return ' url1: '.$url1. ' # '.$url2;
});

1

Hãy thử regex này:

    Route::get('/{url1}', function ($url1) {
        return 'url: '.url1;
    })->where('url1', '^(?!(string1|string2)$)(\S+)');

thankiu, nhưng khi tôi thử http://domain/string1/abcnó vẫn tìm thấy?
DeLe

1

Thay vì viết một tuyến đường để khớp với bất kỳ thứ gì ngoài các chuỗi tĩnh nhất định, tôi thấy rõ ràng hơn khi viết hai tuyến đường: một tuyến đường khớp với các chuỗi tĩnh nhất định và một tuyến đường khác để khớp với mọi thứ khác.

// route that matches forbidden static strings, optionally with a postfix slug
$router->get('/{forbidden}/{optional_path?}', function () {
    return response('Not found', 404);
})->where([ 'forbidden' => '(?:string1|string2)', 'optional_path' => '.*' ]);

// route that matches anything else (order of definition matters, must be last)
// might also consider using Route::fallback(), but I prefer to leave that
// alone in case my future self changes this below and opens up a hole
$router->get('/{anything?}', function () {
    return response('Found', 200);
})->where([ 'anything' => '.*' ]);

Kết quả nào trong * :

  • domain => 200 Tìm thấy
  • domain/ => 200 Tìm thấy
  • domain/abc => 200 Tìm thấy
  • domain/string1 => 404 Không tìm thấy
  • domain/string1/ => 404 Không tìm thấy
  • domain/string1/abc => 404 Không tìm thấy
  • domain/string10 => 200 Tìm thấy
  • domain/string10/ => 200 Tìm thấy
  • domain/string10/abc => 200 Tìm thấy
  • domain/string2 => 404 Không tìm thấy
  • domain/string2/ => 404 Không tìm thấy
  • domain/string2/abc => 404 Không tìm thấy
  • domain/string20 => 200 Tìm thấy
  • domain/string20/ => 200 Tìm thấy
  • domain/string20/abc => 200 Tìm thấy

Tôi thấy điều này rõ ràng hơn, vì tôi không phải suy nghĩ về các loại trừ. Thay vào đó, tôi có thể nghĩ đến việc khớp chính xác những gì tôi muốn cấm, sau đó để cho Laravel phản ứng với mọi thứ khác (thất bại trong chính sách mở). Điều này có thể không đáp ứng các tiêu chí thiết kế của bạn, nhưng tôi tin rằng nó dẫn đến mã rõ ràng hơn.

Ngoài ra, mã là hiệu suất hơn. ?!phải quay lại, theo định nghĩa là đắt hơn so với kết hợp chuyển tiếp.

Tôi không có môi trường Laravel trong tay, nhưng tôi sẽ đoán xem tại sao những nỗ lực của bạn không hiệu quả. Laravel sử dụng Symfony Router, không hỗ trợ nhìn trên sên . IIRC, khi phát hiện ra một cái nhìn, Symfony áp dụng giao diện đó cho toàn bộ URL, chứ không phải con sên mà bạn đã ràng buộc mẫu. Điều này gây rối với ý tưởng của nhà phát triển về cách các ký tự meta (^, $) và meta (*) tham lam hoạt động. Điều này có thể dẫn đến một trải nghiệm tồi tệ khi cố gắng làm cho nó hoạt động, vì nhà phát triển hoạt động theo một giả định nhưng các thư viện cơ bản hoạt động trên một cái khác.


* Tiết lộ đầy đủ, tôi đã viết cái này cho Lumen sau đó chuyển đổi nó thành định dạng Laravel. Có thể có một số lỗi dịch thuật. Đây là Lumen gốc:

$router->get('/{forbidden:(?:string1|string2)}[/{optional_path:.*}]', function () {
    return response('Not found', 404);
});
$router->get('{anything:.*}', function () {                                   
    return response('Found', 200);
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.