Laravel - a rota regex corresponde a tudo, mas não exatamente uma ou mais palavras

8

Eu faço uma rota como

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

e url de acesso como:
- domain/abc não encontrado => incorreto ??
- domain/string1não encontrado => correto

e mais, quando eu faço com

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

e url de acesso como:
- domain/abc/abc não encontrado => incorreto ???
- domain/string1/abcnão encontrado => correto

Como consertar esse agradecimento

DeLe
fonte
Onde string será estática ou dinâmica?
Mitesh Rathod 01/01
@MiteshRathod string1 e string2 é uma palavra especial (estática)
DeLe
somente essa string 2 não aceita no url, correto?
Mitesh Rathod 01/01
@MiteshRathod sim, string1 ou string2 não serão aceitos em url
DeLe
Adicione sua expressão regular exata.
revo

Respostas:

3

Por favor, tente com isso para o 1º cenário:

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

para o segundo cenário:

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

espero que esta ajuda :)

Mitesh Rathod
fonte
thankiu mas, eu apenas tente primeiro com domain/abcmas não foi encontrado?
DeLe 1/01
3

Tente isto

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

Maneira impura de conseguir isso

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

Mais uma maneira de experimentar usando RouteServiceProvider.php

Mude o seu boot()assim.

public function boot()
    {
        //
        Route::pattern('url1', '^(?!string1$|string2$)([a-zA-Z0-9-]+)');
        Route::pattern('url2', '^(?!string1$|string2$)([a-zA-Z0-9-]+)');
        parent::boot();
    }
Prashant Deshmukh .....
fonte
thankiu, mas não está funcionando bem. Eu apenas tento domain/string1=> ele ainda encontrou
DeLe
@DeLe estranho eu tentei o mesmo código, mas s excluding 127.0.0.1:8000/domain/string2 , 127.0.0.1:8000/domain/string1 `e trabalhando parahttp://127.0.0.1:8000/domain/abc
Prashant Deshmukh ..... 01/01
desculpe domain, domaingosto http://127.0.0.1:8000e você deve tentar 127.0.0.1:8000/string1, ...
DeLe 1/01
@DeLe Atualizado, verifique agora.
Prashant Deshmukh ..... 01/01
1
@DeLe Confira a resposta atualizada usando RouteServiceProvider.
Prashant Deshmukh ..... 03/01
3

Após os testes, acho impossível conseguir exatamente o que você deseja. Parece que você deseja excluir string1e string2precisa concordar que também as strings que começam com string1e string2serão excluídas (por exemplo string1aaa).

Ao usar essas rotas:

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)[^\/]+');

O resultado será:

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

Eu acredito que essa limitação vem do Laravel e não do regex. Se você precisa aceitar também parâmetros iniciados com string1e string2acredito que você deve fazê-lo da maneira manual, como segue:

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;
});
Marcin Nabiałek
fonte
1

Experimente esta regex:

    Route::get('/{url1}', function ($url1) {
        return 'url: '.url1;
    })->where('url1', '^(?!(string1|string2)$)(\S+)');
TsaiKoga
fonte
thankiu, mas quando eu tento http://domain/string1/abcainda encontrado?
DeLe 1/01
1

Em vez de escrever uma rota para corresponder a algo diferente de certas seqüências de caracteres estáticas, acho mais claro escrever duas rotas: uma rota para corresponder a certas seqüências estáticas e outra rota para corresponder a todo o resto.

// 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' => '.*' ]);

O que resulta em * :

  • domain => 200 encontrado
  • domain/ => 200 encontrado
  • domain/abc => 200 encontrado
  • domain/string1 => 404 Não encontrado
  • domain/string1/ => 404 Não encontrado
  • domain/string1/abc => 404 Não encontrado
  • domain/string10 => 200 encontrado
  • domain/string10/ => 200 encontrado
  • domain/string10/abc => 200 encontrado
  • domain/string2 => 404 Não encontrado
  • domain/string2/ => 404 Não encontrado
  • domain/string2/abc => 404 Não encontrado
  • domain/string20 => 200 encontrado
  • domain/string20/ => 200 encontrado
  • domain/string20/abc => 200 encontrado

Acho isso mais claro, porque não preciso pensar em termos de exclusões. Em vez disso, posso pensar em combinar exatamente o que quero proibir e deixar o Laravel reagir a todo o resto (falha na política de abertura). Isso pode não atender aos seus critérios de design, mas acredito que resulta em um código mais claro.

Além disso, o código é mais eficiente. ?!precisa voltar atrás, o que, por definição, é mais caro que a correspondência direta.

Não tenho um ambiente Laravel à mão, mas arriscarei um palpite sobre por que suas tentativas não funcionaram. O Laravel usa o Symfony Router, que não suporta buscas em slugs . IIRC, quando uma busca é detectada, o Symfony aplica a busca a toda a URL, não à lesma à qual você vinculou o padrão. Isso mexe com a idéia do desenvolvedor de como os meta-caracteres âncoras (^, $) e gananciosos (*) funcionam. Isso pode levar a uma experiência ruim na tentativa de fazê-lo funcionar, pois o desenvolvedor opera sob uma suposição, mas as bibliotecas subjacentes operam em outra.


* Divulgação completa, escrevi isso para o Lumen e depois o converti mentalmente para o formato Laravel. É possível que haja alguns erros de tradução. Aqui está o Lumen original:

$router->get('/{forbidden:(?:string1|string2)}[/{optional_path:.*}]', function () {
    return response('Not found', 404);
});
$router->get('{anything:.*}', function () {                                   
    return response('Found', 200);
});
bispo
fonte