Laravel: la ruta de expresión regular coincide con todo pero no exactamente con una o más palabras

8

Hago una ruta como

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

y acceder a la URL como:
- domain/abc no encontrado => incorrecto ??
- domain/string1no encontrado => correcto

y más, cuando hago con

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

y acceder a la URL como:
- domain/abc/abc no encontrado => incorrecto ???
- domain/string1/abcno encontrado => correcto

Cómo arreglar ese agradecimiento

Siglo de dele
fuente
¿En dónde la cadena será estática o dinámica?
Mitesh Rathod
@MiteshRathod string1 y string2 es una palabra especial (es estática)
DeLe
solo esta cadena 2 no acepta en url, ¿correcto?
Mitesh Rathod
@MiteshRathod sí, string1 o string2 no se aceptarán en la url
DeLe
Por favor agregue su expresión regular exacta.
revo

Respuestas:

3

Intente con esto para el 1er escenario:

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

para el 2do escenario:

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

espero esta ayuda :)

Mitesh Rathod
fuente
gracias pero, solo intento primero con domain/abcpero no se encuentra?
DeLe
3

Prueba esto

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

Manera sucia de lograr esto

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

Una forma más en la que he intentado usando RouteServiceProvider.php

Cambia tu boot()así.

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 .....
fuente
gracias, pero no funciona bien. Solo intento domain/string1=> todavía se encuentra
DeLe
@DeLe extraño He intentado el mismo código, pero s excluding 127.0.0.1:8000/domain/string2 , 127.0.0.1:8000/domain/string1 `y estoy trabajando parahttp://127.0.0.1:8000/domain/abc
Prashant Deshmukh .....
lo siento domain, me domaingusta http://127.0.0.1:8000y deberías probar 127.0.0.1:8000/string1...
DeLe
@DeLe Actualizado, verifique ahora.
Prashant Deshmukh .....
1
@DeLe Consulte la respuesta actualizada con RouteServiceProvider.
Prashant Deshmukh .....
3

Después de las pruebas, creo que es imposible lograr exactamente lo que quieres. Parece cuando desea excluir string1y string2debe aceptar que también las cadenas que comienzan con string1y string2serán excluidas (por ejemplo string1aaa).

Al usar tales rutas:

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

el 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

Creo que dicha limitación proviene de Laravel y no de regex. Si necesita aceptar también los parámetros que comienzan con string1y string2creo que debe hacerlo de manera manual de la siguiente manera:

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
fuente
1

Prueba esta expresión regular:

    Route::get('/{url1}', function ($url1) {
        return 'url: '.url1;
    })->where('url1', '^(?!(string1|string2)$)(\S+)');
TsaiKoga
fuente
thankiu, pero cuando lo intento http://domain/string1/abctodavía se encuentra?
DeLe
1

En lugar de escribir una ruta para que coincida con cualquier otra cosa que no sean ciertas cadenas estáticas, me resulta más claro escribir dos rutas: una ruta para que coincida con ciertas cadenas estáticas, y otra ruta para que coincida con todo lo demás.

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

Lo que resulta en * :

  • domain => 200 encontrados
  • domain/ => 200 encontrados
  • domain/abc => 200 encontrados
  • domain/string1 => 404 No encontrado
  • domain/string1/ => 404 No encontrado
  • domain/string1/abc => 404 No encontrado
  • domain/string10 => 200 encontrados
  • domain/string10/ => 200 encontrados
  • domain/string10/abc => 200 encontrados
  • domain/string2 => 404 No encontrado
  • domain/string2/ => 404 No encontrado
  • domain/string2/abc => 404 No encontrado
  • domain/string20 => 200 encontrados
  • domain/string20/ => 200 encontrados
  • domain/string20/abc => 200 encontrados

Me parece más claro, porque no tengo que pensar en términos de exclusiones. Por el contrario, puedo pensar en igualar exactamente lo que quiero prohibir, y luego dejar que Laravel reaccione a todo lo demás (política abierta fallida). Es posible que esto no cumpla con sus criterios de diseño, pero creo que da como resultado un código más claro.

Además, el código es más eficiente. ?!tiene que retroceder, que es, por definición, más costoso que la correspondencia hacia adelante.

No tengo un entorno Laravel a mano, pero me arriesgaré a adivinar por qué tus intentos no funcionaron. Laravel utiliza Symfony Router, que no admite búsquedas en babosas . IIRC, cuando se detecta una búsqueda, Symfony aplica la búsqueda a toda la URL, no a la babosa a la que ha vinculado el patrón. Esto se mete con la idea del desarrollador de cómo funcionan los metacaracteres de anclajes (^, $) y codiciosos (*). Esto puede conducir a una mala experiencia al intentar que funcione, ya que el desarrollador opera bajo una suposición pero las bibliotecas subyacentes operan en otra.


* Revelación completa, escribí esto para Lumen y luego lo convertí mentalmente al formato Laravel. Es posible que haya algunos errores de traducción. Aquí está el Lumen original:

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