Die Laravel-Regex-Route entspricht allem, aber nicht genau einem oder mehreren Wörtern

8

Ich mache eine Route wie

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

und Zugriff URL wie:
- domain/abc nicht gefunden => falsch ?
- domain/string1nicht gefunden => richtig

und mehr, wenn ich mit mache

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

und Zugriff URL wie:
- domain/abc/abc nicht gefunden => falsch ???
- domain/string1/abcnicht gefunden => richtig

Wie man das behebt, danke

DeLe
quelle
Wo wird der String statisch oder dynamisch sein?
Mitesh Rathod
@MiteshRathod string1 und string2 ist ein spezielles Wort (es ist statisch)
DeLe
nur diese 2 Zeichenfolge nicht in URL akzeptieren, richtig?
Mitesh Rathod
@MiteshRathod Ja, String1 oder String2 werden in der URL nicht akzeptiert
DeLe
Bitte fügen Sie Ihren genauen regulären Ausdruck hinzu.
Revo

Antworten:

3

Bitte versuchen Sie dies für das erste Szenario:

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

für das 2. Szenario:

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

Ich hoffe diese Hilfe :)

Mitesh Rathod
quelle
danke aber ich versuche nur 1. mit domain/abcaber es ist nicht gefunden?
DeLe
3

Versuche dies

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

Unreiner Weg, um dies zu erreichen

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

Eine weitere Möglichkeit habe ich mit versucht RouteServiceProvider.php

Ändere dein boot()so.

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 .....
quelle
danke, aber es funktioniert nicht gut. Ich versuche domain/string1es einfach => es wurde immer noch gefunden
DeLe
@DeLe seltsam Ich habe den gleichen Code ausprobiert, aber er s excluding 127.0.0.1:8000/domain/string2 , 127.0.0.1:8000/domain/string1 `und arbeitet fürhttp://127.0.0.1:8000/domain/abc
Prashant Deshmukh .....
Entschuldigung domain, domainwie http://127.0.0.1:8000und du solltest es versuchen 127.0.0.1:8000/string1, ...
DeLe
@DeLe Aktualisiert, jetzt überprüfen.
Prashant Deshmukh .....
1
@DeLe Überprüfen Sie die aktualisierte Antwort mit RouteServiceProvider.
Prashant Deshmukh .....
3

Nach Tests denke ich, dass es unmöglich ist, genau das zu erreichen, was Sie wollen. Es scheint, wenn Sie ausschließen möchten string1und string2Sie müssen zustimmen, dass auch Zeichenfolgen, die mit beginnen string1und string2ausgeschlossen werden (so zum Beispiel string1aaa).

Bei Verwendung solcher Routen:

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

Ergebnis wird sein:

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

Ich glaube, eine solche Einschränkung kommt von Laravel und nicht von Regex. Wenn Sie auch Parameter akzeptieren müssen, die mit beginnen, string1und string2ich glaube, Sie müssen dies manuell tun:

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

Versuchen Sie diesen regulären Ausdruck:

    Route::get('/{url1}', function ($url1) {
        return 'url: '.url1;
    })->where('url1', '^(?!(string1|string2)$)(\S+)');
TsaiKoga
quelle
danke, aber wenn ich es versuche http://domain/string1/abcnoch gefunden?
DeLe
1

Anstatt eine Route zu schreiben, die mit etwas anderem als bestimmten statischen Zeichenfolgen übereinstimmt , finde ich es klarer, zwei Routen zu schreiben: eine Route, die mit bestimmten statischen Zeichenfolgen übereinstimmt, und eine andere Route, die mit allem anderen übereinstimmt.

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

Was zu * führt :

  • domain => 200 gefunden
  • domain/ => 200 gefunden
  • domain/abc => 200 gefunden
  • domain/string1 => 404 Nicht gefunden
  • domain/string1/ => 404 Nicht gefunden
  • domain/string1/abc => 404 Nicht gefunden
  • domain/string10 => 200 gefunden
  • domain/string10/ => 200 gefunden
  • domain/string10/abc => 200 gefunden
  • domain/string2 => 404 Nicht gefunden
  • domain/string2/ => 404 Nicht gefunden
  • domain/string2/abc => 404 Nicht gefunden
  • domain/string20 => 200 gefunden
  • domain/string20/ => 200 gefunden
  • domain/string20/abc => 200 gefunden

Ich finde das klarer, weil ich nicht in Ausschlüssen denken muss. Ich kann mir vielmehr vorstellen, genau das zu finden, was ich verbieten möchte, und dann Laravel auf alles andere reagieren zu lassen (Fail Open Policy). Dies entspricht möglicherweise nicht Ihren Entwurfskriterien, aber ich glaube, dass dies zu einem klareren Code führt.

Außerdem ist der Code leistungsfähiger. ?!muss zurückverfolgen, was per Definition teurer ist als Forward Matching.

Ich habe keine Laravel-Umgebung zur Hand, aber ich riskiere eine Vermutung, warum Ihre Versuche nicht funktioniert haben. Laravel verwendet Symfony Router, der keine Lookarounds für Slugs unterstützt . IIRC: Wenn eine Lookaround erkannt wird, wendet Symfony die Lookaround auf die gesamte URL an, nicht auf den Slug, an den Sie das Muster gebunden haben. Dies steht im Widerspruch zu der Vorstellung des Entwicklers, wie Anker (^, $) und gierige (*) Metazeichen funktionieren. Dies kann zu einer schlechten Erfahrung beim Versuch führen, es zum Laufen zu bringen, da der Entwickler unter einer Annahme arbeitet, die zugrunde liegenden Bibliotheken jedoch unter einer anderen.


* Vollständige Offenlegung, ich habe dies für Lumen geschrieben und es dann mental in das Laravel-Format konvertiert. Möglicherweise gibt es einige Übersetzungsfehler. Hier ist das ursprüngliche Lumen:

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