Zum Inhalt

validation: Validierungsbibliothek (Eingabevalidierung und -filterung) für Lua und nginx-module-lua

Installation

Wenn Sie das RPM-Repository-Abonnement noch nicht eingerichtet haben, melden Sie sich an. Dann können Sie mit den folgenden Schritten fortfahren.

CentOS/RHEL 7 oder Amazon Linux 2

yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-validation

CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023

dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-validation

Um diese Lua-Bibliothek mit NGINX zu verwenden, stellen Sie sicher, dass nginx-module-lua installiert ist.

Dieses Dokument beschreibt lua-resty-validation v2.7, das am 25. August 2017 veröffentlicht wurde.


lua-resty-validation ist eine erweiterbare Kettenvalidierungs- und Filterbibliothek für Lua und OpenResty.

Hallo Welt mit lua-resty-validation

local validation = require "resty.validation"

local valid, e = validation.number:between(0, 9)(5)  -- valid = true,  e = 5
local valid, e = validation.number:between(0, 9)(50) -- valid = false, e = "between"

-- Validatoren können wiederverwendet werden
local smallnumber = validation.number:between(0, 9)
local valid, e = smallnumber(5)  -- valid = true,  e = 5
local valid, e = smallnumber(50) -- valid = false, e = "between"

-- Validatoren können auch filtern (d.h. den zu validierenden Wert ändern)
-- valid = true, s = "HELLO WORLD!"
local valid, s = validation.string.upper "hello world!"

-- Sie können die Validierungsbibliothek mit eigenen Validatoren und Filtern erweitern...
validation.validators.capitalize = function(value) 
    return true, value:gsub("^%l", string.upper)
end

-- ... und dann verwenden
local valid, e = validation.capitalize "abc" -- valid = true,  e = "Abc"

-- Sie können auch mehrere Werte gruppenvalidieren
local group = validation.new{
    artist = validation.string:minlen(5),
    number = validation.tonumber:equal(10)
}

local valid, fields, errors = group{ artist = "Eddie Vedder", number = "10" }

if valid then
  print("alle Gruppenfelder sind gültig")
else
  print(fields.artist.name,      fields.artist.error,
        fields.artist.valid,     fields.artist.invalid,
        fields.artist.input,     fields.artist.value, ,
        fields.artist.validated, fields.artist.unvalidated)
end

-- Sie können sogar Felder aufrufen, um einfache Name-Wert-Tabellen zu erhalten
-- (in diesem Fall werden alle `nil`s ebenfalls entfernt)

-- Standardmäßig gibt dies nur die Namen und Werte der gültigen Felder zurück:
local data = fields()
local data = fields "valid"

-- Um nur die Namen und Werte der ungültigen Felder zu erhalten, rufen Sie an:
local data = fields "invalid"

-- Um nur die Namen und Werte der validierten Felder zu erhalten (unabhängig davon, ob sie gültig sind oder nicht):
local data = fields "validated"

-- Um nur die Namen und Werte der nicht validierten Felder zu erhalten (unabhängig davon, ob sie gültig sind oder nicht):
local data = fields "unvalidated"

-- Um alles zu erhalten, rufen Sie an:
local data = fields "all"

-- Oder kombinieren:
local data = fields("valid", "invalid")

-- Das hört hier nicht auf. Sie möchten möglicherweise auch nur einige Felder nach ihrem Namen abrufen.
-- Sie können dies tun, indem Sie aufrufen (gibt eine Tabelle zurück):
local data = data{ "artist" }

Eingebaute Validatoren und Filter

lua-resty-validation kommt mit mehreren eingebauten Validatoren, und das Projekt ist offen für Beiträge von weiteren Validatoren.

Validatoren und Filter ohne Argumente

Typvalidatoren können verwendet werden, um den Typ des validierten Wertes zu überprüfen. Diese Validatoren sind argumentlose Validatoren (rufen Sie sie mit Punkt . auf):

  • null oder ["nil"] (da nil ein reserviertes Schlüsselwort in Lua ist)
  • boolean
  • number
  • string
  • table
  • userdata
  • func oder ["function"] (da function ein reserviertes Schlüsselwort in Lua ist)
  • callable (entweder eine Funktion oder eine Tabelle mit Metamethode __call)
  • thread
  • integer
  • float
  • file (io.type(value) == 'file')

Typumwandlungsfilter:

  • tostring
  • tonumber
  • tointeger
  • toboolean

Andere Filter:

  • tonil oder tonull
  • abs
  • inf
  • nan
  • finite
  • positive
  • negative
  • lower
  • upper
  • trim
  • ltrim
  • rtrim
  • reverse
  • email
  • optional

Beispiel

local validation = require "resty.validation"
local ok, e = validation.null(nil)
local ok, e = validation.boolean(true)
local ok, e = validation.number(5.2)
local ok, e = validation.string('Hello, World!')
local ok, e = validation.integer(10)
local ok, e = validation.float(math.pi)
local f = assert(io.open('filename.txt', "r"))
local ok, e = validation.file(f)

Validierungsfabrik-Validatoren und -Filter

Die Validierungsfabrik besteht aus verschiedenen Validatoren und Filtern, die verwendet werden, um den Wert zu validieren oder zu filtern (rufen Sie sie mit Doppelpunkt : auf):

  • type(t), validiert, dass der Wert vom Typ t ist (siehe Typvalidatoren)
  • nil() oder ["null"](), überprüft, dass der Werttyp nil ist
  • boolean(), überprüft, dass der Werttyp boolean ist
  • number(), überprüft, dass der Werttyp number ist
  • string(), überprüft, dass der Werttyp string ist
  • table(), überprüft, dass der Werttyp table ist
  • userdata(), überprüft, dass der Werttyp userdata ist
  • func() oder ["function"](), überprüft, dass der Werttyp function ist
  • callable(), überprüft, dass der Wert aufrufbar ist (d.h. eine Funktion oder eine Tabelle mit Metamethode __call)
  • thread(), überprüft, dass der Werttyp thread ist
  • integer(), überprüft, dass der Werttyp integer ist
  • float(), überprüft, dass der Werttyp float ist
  • file(), überprüft, dass der Werttyp file ist (io.type(value) == 'file')
  • abs(), filtert den Wert und gibt den absoluten Wert zurück (math.abs)
  • inf(), überprüft, dass der Wert inf oder -inf ist
  • nan(), überprüft, dass der Wert nan ist
  • finite(), überprüft, dass der Wert nicht nan, inf oder -inf ist
  • positive(), validiert, dass der Wert positiv ist (> 0)
  • negative(), validiert, dass der Wert negativ ist (< 0)
  • min(min), validiert, dass der Wert mindestens min ist (>=)
  • max(max), validiert, dass der Wert höchstens max ist (<=)
  • between(min[, max = min]), validiert, dass der Wert zwischen min und max liegt
  • outside(min[, max = min]), validiert, dass der Wert nicht zwischen min und max liegt
  • divisible(number), validiert, dass der Wert durch number teilbar ist
  • indivisible(number), validiert, dass der Wert nicht durch number teilbar ist
  • len(min[, max = min]), validiert, dass die Länge des Wertes genau min oder zwischen min und max liegt (UTF-8)
  • minlen(min), validiert, dass die Länge des Wertes mindestens min ist (UTF-8)
  • maxlen(max), validiert, dass die Länge des Wertes höchstens max ist (UTF-8)
  • equals(equal) oder equal(equal), validiert, dass der Wert genau etwas ist
  • unequals(equal) oder unequal(equal), validiert, dass der Wert nicht genau etwas ist
  • oneof(...), validiert, dass der Wert gleich einem der angegebenen Argumente ist
  • noneof(...), validiert, dass der Wert nicht gleich einem der angegebenen Argumente ist
  • match(pattern[, init]), validiert, dass der Wert dem Muster entspricht (string.match)
  • unmatch(pattern[, init]), validiert, dass der Wert nicht dem Muster entspricht (string.match)
  • tostring(), konvertiert den Wert in einen String
  • tonumber([base]), konvertiert den Wert in eine Zahl
  • tointeger(), konvertiert den Wert in eine Ganzzahl
  • toboolean(), konvertiert den Wert in einen Boolean (unter Verwendung von not not value)
  • tonil() oder tonull(), konvertiert den Wert in nil
  • lower(), konvertiert den Wert in Kleinbuchstaben (UTF-8-Unterstützung ist noch nicht implementiert)
  • upper(), konvertiert den Wert in Großbuchstaben (UTF-8-Unterstützung ist noch nicht implementiert)
  • trim([pattern]), entfernt Leerzeichen (Sie können auch ein Muster verwenden) von links und rechts
  • ltrim([pattern]), entfernt Leerzeichen (Sie können auch ein Muster verwenden) von links
  • rtrim([pattern]), entfernt Leerzeichen (Sie können auch ein Muster verwenden) von rechts
  • starts(starts), überprüft, ob der String mit starts beginnt
  • ends(ends), überprüft, ob der String mit ends endet
  • reverse, kehrt den Wert um (String oder Zahl) (UTF-8)
  • coalesce(...), wenn der Wert nil ist, gibt den ersten nicht-nil-Wert zurück, der als Argumente übergeben wurde
  • email(), validiert, dass der Wert eine E-Mail-Adresse ist
  • call(function), validiert / filtert den Wert gegen einen benutzerdefinierten Inline-Validator / Filter
  • optional([default]), stoppt die Validierung, wenn der Wert ein leerer String "" oder nil ist, und gibt true zurück, und entweder default oder value

Bedingte Validierungsfabrik-Validatoren

Für alle Validierungsfabrik-Validatoren gibt es eine bedingte Version, die immer auf true validiert, aber bei der Sie den tatsächlichen Wert ersetzen können, je nachdem, ob der ursprüngliche Validator validiert hat. Hey, das ist einfacher zu zeigen als zu sagen:

local validation = require "resty.validation"

-- ok == true, value == "Ja, der Wert ist nil"
local ok, value = validation:ifnil(
    "Ja, der Wert ist nil",
    "Nein, Sie haben keinen nil-Wert angegeben")(nil)

-- ok == true, value == "Nein, Sie haben keinen nil-Wert angegeben"
local ok, value = validation:ifnil(
    "Ja, der Wert ist nil",
    "Nein, Sie haben keinen nil-Wert angegeben")("non nil")

-- ok == true, value == "Ja, die Zahl liegt zwischen 1 und 10"    
local ok, value = validation:ifbetween(1, 10,
    "Ja, die Zahl liegt zwischen 1 und 10",
    "Nein, die Zahl liegt nicht zwischen 1 und 10")(5)

-- ok == true, value == "Nein, die Zahl liegt nicht zwischen 1 und 10"
local ok, value = validation:ifbetween(1, 10,
    "Ja, die Zahl liegt zwischen 1 und 10",
    "Nein, die Zahl liegt nicht zwischen 1 und 10")(100)

Die letzten 2 Argumente für bedingte Validierungsfabrik-Validatoren sind die truthy und falsy Werte. Jedes andere Argument wird an den tatsächlichen Validierungsfabrik-Validator übergeben.

Gruppen-Validatoren

lua-resty-validation unterstützt derzeit einige vordefinierte Validatoren:

  • compare(comparison), vergleicht zwei Felder und setzt die Felder entsprechend dem Vergleich ungültig oder gültig
  • requisite{ fields }, mindestens eines der erforderlichen Felder ist erforderlich, auch wenn sie für sich genommen optional sind
  • requisites({ fields }, number), mindestens number der erforderlichen Felder sind erforderlich (standardmäßig alle)
  • call(function), ruft eine benutzerdefinierte (oder Inline-)Gruppenvalidierungsfunktion auf
local ispassword = validation.trim:minlen(8)
local group = validation.new{
    password1 = ispassword,
    password2 = ispassword
}
group:compare "password1 == password2"
local valid, fields, errors = group{ password1 = "qwerty123", password2 = "qwerty123" }

local optional = validation:optional"".trim
local group = validation.new{
    text = optional,
    html = optional
}
group:requisite{ "text", "html" }
local valid, fields, errors = group{ text = "", html = "" }


local optional = validation:optional ""
local group = validation.new{
    text = optional,
    html = optional
}
group:requisites({ "text", "html" }, 2)
-- oder group:requisites{ "text", "html" }
local valid, fields, errors = group{ text = "", html = "" }


group:call(function(fields)
    if fields.text.value == "hello" then
        fields.text:reject "text darf nicht 'hello' sein"
        fields.html:reject "da der Text 'hello' war, ist dieses Feld ebenfalls ungültig"
    end
end)

Sie können normale Lua-Vergleichsoperatoren im compare Gruppenvalidator verwenden:

  • <
  • >
  • <=
  • >=
  • ==
  • ~=

requisite und requisites überprüfen, ob der Feldwert nil oder "" (leerer String) ist. Bei requisite, wenn alle angegebenen Felder nil oder "" sind, dann sind alle Felder ungültig (vorausgesetzt, sie waren nicht für sich genommen ungültig), und wenn mindestens eines der Felder gültig ist, dann sind alle Felder gültig. requisites funktioniert gleich, aber dort können Sie die Anzahl der Felder definieren, die einen Wert haben sollen, der nicht nil und nicht ein leerer String "" ist. Diese bieten bedingte Validierung im Sinne von:

  1. Ich habe (zwei oder mehr) Felder
  2. Alle sind optional
  3. Mindestens eines / eine definierte Anzahl von Feldern sollte ausgefüllt sein, aber ich kümmere mich nicht darum, welches, solange mindestens eines / eine definierte Anzahl von Feldern ausgefüllt ist

Stop-Validatoren

Stop-Validatoren, wie optional, sind wie normale Validatoren, aber anstatt true oder false als Validierungsergebnis ODER als gefilterten Wert zurückzugeben, können Sie validation.stop zurückgeben. Dieser Wert kann auch innerhalb von bedingten Validatoren und in Validatoren verwendet werden, die Standardwerte unterstützen. Hier ist, wie der optional-Validator implementiert ist:

function factory.optional(default)
    return function(value)
        if value == nil or value == "" then
            return validation.stop, default ~= nil and default or value
        end
        return true, value
    end
end

Diese sind grob gleichwertig:

-- Beide geben zurück: true, "default" (sie stoppen die Verarbeitung :minlen(10) bei nil und "" Eingaben)
local input = ""
local ok, val = validation.optional:minlen(10)(input)
local ok, val = validation:optional(input):minlen(10)(input)
local ok, val = validation:ifoneof("", nil, validation.stop(input), input):minlen(10)(input)

Wert filtern und den Wert auf nil setzen

Die meisten der Validatoren, die den Wert nicht filtern, geben nur true oder false als Ergebnis zurück. Das bedeutet, dass es jetzt keine Möglichkeit gibt, resty.validation zu signalisieren, den Wert tatsächlich auf nil zu setzen. Es gibt also einen Workaround, Sie können validation.nothing als Wert zurückgeben, und das wird den Wert auf nil ändern, z.B. der eingebaute tonil-Validator ist tatsächlich so implementiert (pseudo):

function()
    return true, validation.nothing
end

Benutzerdefinierte (Inline-)Validatoren und Filter

Manchmal haben Sie möglicherweise nur einmalige Validatoren / Filter, die Sie nicht anderswo verwenden oder die Sie einfach schnell für einen bestimmten Fall bereitstellen möchten. Um das einfach und unkompliziert zu machen, haben wir die call-Fabrikmethode mit lua-resty-validation 2.4 eingeführt. Hier ist ein Beispiel:

validation:call(function(value)
    -- jetzt validieren / filtern Sie den Wert und geben Sie die Ergebnisse zurück
    -- hier geben wir einfach false zurück (d.h. die Validierung schlägt fehl)
    return false
end)("Überprüfen Sie diesen Wert"))

(Es muss natürlich nicht eine Inline-Funktion sein, da in Lua alle Funktionen Erstklassige Bürger sind und sie als Parameter übergeben werden können)

Eingebaute Validatorerweiterungen

Derzeit unterstützt lua-resty-validation zwei Erweiterungen oder Plugins, die Sie aktivieren können:

  • resty.validation.ngx
  • resty.validation.tz
  • resty.validation.utf8

Diese sind etwas, das Sie sich ansehen können, wenn Sie Ihre eigene Validatorerweiterung erstellen möchten. Wenn Sie dies tun und denken, dass es auch für andere nützlich sein könnte, denken Sie daran, Ihre Erweiterung als Pull-Request zur Aufnahme in dieses Projekt zu senden, vielen Dank, ;-).

resty.validation.ngx-Erweiterung

Wie der Name schon sagt, erfordert dieses Set von Validatorerweiterungen OpenResty (oder mindestens das Lua Nginx-Modul). Um diese Erweiterung zu verwenden, müssen Sie nur:

require "resty.validation.ngx"

Es wird die Adapter, die es in resty.validation bereitstellt, monkey patchen, und diese sind derzeit:

  • escapeuri
  • unescapeuri
  • base64enc
  • base64dec
  • crc32short
  • crc32long
  • crc32
  • md5

(es gibt sowohl Fabrik- als auch argumentlose Versionen davon)

Es gibt auch einen Regex-Matcher in der ngx-Erweiterung, der ngx.re.match verwendet, und parametrisiertes md5:

  • regex(regex[, options])
  • md5([bin])
Beispiel
require "resty.validation.ngx"
local validation = require "resty.validation"
local valid, value = validation.unescapeuri.crc32("https://github.com/")
local valid, value = validation:unescapeuri():crc32()("https://github.com/")

resty.validation.tz-Erweiterung

Dieses Set von Validatoren und Filtern basiert auf der großartigen luatz Bibliothek von @daurnimator, die eine Bibliothek für Zeit- und Datumsmanipulation ist. Um diese Erweiterung zu verwenden, müssen Sie nur:

require "resty.validation.tz"

Es wird die Adapter, die es in resty.validation bereitstellt, monkey patchen, und diese sind derzeit:

  • totimetable
  • totimestamp

(es gibt sowohl Fabrik- als auch argumentlose Versionen davon)

totimestamp und totimetable Filter funktionieren hervorragend mit HTML5-Daten- und Datetime-Eingabefeldern. Wie der Name schon sagt, gibt totimetable luatz timetable zurück und totimestamp gibt Sekunden seit dem Unix-Epoch (1970-01-01) als Lua-Zahl zurück.

Beispiel
require "resty.validation.tz"
local validation = require "resty.validation"
local valid, ts = validation.totimestamp("1990-12-31T23:59:60Z")
local valid, ts = validation.totimestamp("1996-12-19")

resty.validation.utf8-Erweiterung

Dieses Set von Validatoren und Filtern basiert auf der großartigen utf8rewind Bibliothek von Quinten Lansu - einer Systembibliothek, die in C geschrieben wurde und die Standard-String-Verarbeitungsfunktionen mit Unterstützung für UTF-8-kodierten Text erweitert. Es benötigt meinen LuaJIT FFI-Wrapper lua-resty-utf8rewind, um zu funktionieren. Wenn die genannten Anforderungen installiert sind, ist der Rest einfach. Um diese Erweiterung zu verwenden, müssen Sie nur:

require "resty.validation.utf8"

Es wird die Adapter, die es in resty.validation bereitstellt, monkey patchen, und diese sind derzeit:

  • utf8upper
  • utf8lower
  • utf8title

(es gibt sowohl Fabrik- als auch argumentlose Versionen davon)

Es gibt auch einige Fabrik-Validatoren / Filter:

  • utf8normalize(form)
  • utf8category(category)

Der utf8normalize normalisiert die UTF-8-Eingabe in eines dieser Normalisierungsformate:

  • C (oder NFC)
  • D (oder NFD)
  • KC (oder NFKC)
  • KD (oder NFKD)

Der utf8category überprüft, dass der Eingabestring in einer der folgenden Kategorien ist (Sie können also denken, dass es mehrere eingebaute Validatoren gibt, die mit der Validierung von UTF-8-Strings arbeiten):

  • LETTER_UPPERCASE
  • LETTER_LOWERCASE
  • LETTER_TITLECASE
  • LETTER_MODIFIER
  • CASE_MAPPED
  • LETTER_OTHER
  • LETTER
  • MARK_NON_SPACING
  • MARK_SPACING
  • MARK_ENCLOSING
  • MARK
  • NUMBER_DECIMAL
  • NUMBER_LETTER
  • NUMBER_OTHER
  • NUMBER
  • PUNCTUATION_CONNECTOR
  • PUNCTUATION_DASH
  • PUNCTUATION_OPEN
  • PUNCTUATION_CLOSE
  • PUNCTUATION_INITIAL
  • PUNCTUATION_FINAL
  • PUNCTUATION_OTHER
  • PUNCTUATION
  • SYMBOL_MATH
  • SYMBOL_CURRENCY
  • SYMBOL_MODIFIER
  • SYMBOL_OTHER
  • SYMBOL
  • SEPARATOR_SPACE
  • SEPARATOR_LINE
  • SEPARATOR_PARAGRAPH
  • SEPARATOR
  • CONTROL
  • FORMAT
  • SURROGATE
  • PRIVATE_USE
  • UNASSIGNED
  • COMPATIBILITY
  • ISUPPER
  • ISLOWER
  • ISALPHA
  • ISDIGIT
  • ISALNUM
  • ISPUNCT
  • ISGRAPH
  • ISSPACE
  • ISPRINT
  • ISCNTRL
  • ISXDIGIT
  • ISBLANK
  • IGNORE_GRAPHEME_CLUSTER
Beispiel
require "resty.validation.utf8"
local validation = require "resty.validation"
local valid, ts = validation:utf8category("LETTER_UPPERCASE")("TEST")

resty.validation.injection-Erweiterung

Dieses Set von Validatoren und Filtern basiert auf der großartigen libinjection Bibliothek von Nick Galbreath - einem SQL / SQLI / XSS-Tokenizer-Parser-Analyzer. Es benötigt meinen LuaJIT FFI-Wrapper lua-resty-injection, um zu funktionieren. Wenn die genannten Anforderungen installiert sind, ist der Rest einfach. Um diese Erweiterung zu verwenden, müssen Sie nur:

require "resty.validation.injection"

Es wird die Adapter, die es in resty.validation bereitstellt, monkey patchen, und diese sind derzeit:

  • sqli, gibt false zurück, wenn SQL-Injection erkannt wurde, andernfalls true
  • xss, gibt false zurück, wenn Cross-Site-Scripting-Injection erkannt wurde, andernfalls true
Beispiel
require "resty.validation.injection"
local validation = require "resty.validation"
local valid, ts = validation.sqli("test'; DELETE FROM users;")
local valid, ts = validation.xss("test <script>alert('XSS');</script>")

API

Ich werde hier nicht auf die Details aller verschiedenen Validatoren und Filter eingehen, da sie alle derselben Logik folgen, aber ich werde einige allgemeine Möglichkeiten zeigen, wie dies funktioniert.

validation._VERSION

Dieses Feld enthält eine Version der Validierungsbibliothek, z.B. kann ihr Wert "2.5" für die Version 2.5 dieser Bibliothek sein.

boolean, value/error validation...

Das ... bedeutet die Validierungskette. Dies wird verwendet, um eine einzelne Validatorenkette zu definieren. Es gibt keine Begrenzung für die Kettenlänge. Es wird immer ein Boolean zurückgegeben (ob die Validierung gültig ist oder nicht). Der zweite Rückgabewert ist entweder der Name des Filters, der nicht true als Validierungsergebnis zurückgegeben hat, oder der gefilterte Wert.

local v = require "resty.validation"

-- Das Folgende bedeutet, erstellen Sie einen Validator, der überprüft, dass die Eingabe:
-- 1. String ist
-- Wenn ja, trimmen Sie Leerzeichen vom Anfang und Ende des Strings:
-- 2. trim
-- Überprüfen Sie dann, dass die Länge des getrimmten Strings mindestens 5 Zeichen (UTF-8) beträgt:
-- 3. minlen(5)
-- Und wenn alles immer noch in Ordnung ist, konvertieren Sie diesen String in Großbuchstaben
-- (UTF-8 wird noch nicht in Großbuchstaben unterstützt):
-- 4. upper
local myvalidator = v.string.trim:minlen(5).upper

-- Dieses Beispiel gibt false und "minlen" zurück
local valid, value = myvalidator(" \n\t a \t\n ")

-- Dieses Beispiel gibt true und "ABCDE" zurück
local valid, value = myvalidator(" \n\t abcde \t\n ")

Immer wenn der Validator fehlschlägt und false zurückgibt, sollten Sie den zurückgegebenen Wert nicht für andere Zwecke als die Fehlerberichterstattung verwenden. So funktioniert die Kette. lua-resty-validation wird nichts versuchen, wenn Sie Ketten angeben, die niemals verwendet werden, wie zum Beispiel:

local v = require "resty.validation"
-- Der Eingabewert kann niemals gleichzeitig sowohl String als auch Zahl sein:
local myvalidator = v.string.number:max(3)
-- Aber Sie könnten dies so schreiben
-- (nehmen Sie die Eingabe als String, versuchen Sie, sie in eine Zahl zu konvertieren, und überprüfen Sie, ob sie höchstens 3 ist):
local myvalidator = v.string.tonumber:max(3)

Wie Sie sehen, ist dies eine Möglichkeit, einzelne wiederverwendbare Validatoren zu definieren. Sie können beispielsweise Ihr Set grundlegender einzelner Validatoren vorab definieren und in Ihrem eigenen Modul speichern, von dem aus Sie dieselbe Validierungslogik in verschiedenen Teilen Ihrer Anwendung wiederverwenden können. Es ist eine gute Idee, zu beginnen, einzelne wiederverwendbare Validatoren zu definieren und sie dann in Gruppen-Validatoren wiederzuverwenden.

Zum Beispiel sagen Sie, Sie haben ein Modul namens validators:

local v = require "resty.validation"
return {
    nick     = v.string.trim:minlen(2),
    email    = v.string.trim.email,
    password = v.string.trim:minlen(8)
}

Und jetzt haben Sie eine register-Funktion irgendwo in Ihrer Anwendung:

local validate = require "validators"
local function register(nick, email, password)
    local vn, nick     = validate.nick(nick)
    local ve, email    = validate.email(email)
    local vp, password = validate.password(password)
    if vn and ve and vp then
        -- Eingabe ist gültig, tun Sie etwas mit nick, email und password
    else
        -- Eingabe ist ungültig, nick, email und password enthalten die Fehlergründe
    end
end

Das wird schnell ein bisschen unordentlich, und deshalb haben wir Gruppen-Validatoren.

table validation.new([Tabelle von Validatoren])

Diese Funktion ist der Punkt, an dem die Gruppenvalidierung beginnt. Angenommen, Sie haben ein Registrierungsformular, das Sie nach Nick, E-Mail (zweimal dasselbe) und Passwort (zweimal dasselbe) fragt.

Wir werden die einzelnen Validatoren wiederverwenden, die im validators-Modul definiert sind:

local v = require "resty.validation"
return {
    nick     = v.string.trim:minlen(2),
    email    = v.string.trim.email,
    password = v.string.trim:minlen(8)
}

Jetzt erstellen wir den wiederverwendbaren Gruppenvalidator im forms-Modul:

local v        = require "resty.validation"
local validate = require "validators"

-- Zuerst erstellen wir einzelne Validatoren für jedes Formularfeld
local register = v.new{
    nick      = validate.nick,
    email     = validate.email,
    email2    = validate.email,
    password  = validate.password,
    password2 = validate.password
}

-- Als nächstes erstellen wir Gruppen-Validatoren für E-Mail und Passwort:
register:compare "email    == email2"
register:compare "password == password2"

-- Und schließlich geben wir aus diesem Formularmodul zurück

return {
    register = register
}

Jetzt haben Sie irgendwo in Ihrer Anwendung diese register-Funktion:

local forms = require "forms"
local function register(data)
    local valid, fields, errors = forms.register(data)
    if valid then
        -- Eingabe ist gültig, tun Sie etwas mit den Feldern
    else
        -- Eingabe ist ungültig, tun Sie etwas mit den Feldern und Fehlern
    end
end

-- Und Sie könnten es so aufrufen:

register{
    nick      = "test",
    email     = "[email protected]",
    email2    = "[email protected]",
    password  = "qwerty123",
    password2 = "qwerty123"
}

Das Tolle an Gruppen-Validatoren ist, dass Sie die Felder und Fehler-Tabellen JSON-codieren und an den Client zurückgeben können. Dies kann nützlich sein, wenn Sie eine Single-Page-Anwendung erstellen und serverseitige Fehler an den Client melden müssen. Im obigen Beispiel wird die fields-Variable so aussehen (valid wäre true, und errors wäre nil):

{
    nick = {
        unvalidated = false,
        value = "test",
        input = "test",
        name = "nick",
        valid = true,
        invalid = false,
        validated = true
    },
    email = {
        unvalidated = false,
        value = "[email protected]",
        input = "[email protected]",
        name = "email",
        valid = true,
        invalid = false,
        validated = true
    },
    email2 = {
        unvalidated = false,
        value = "[email protected]",
        input = "[email protected]",
        name = "email2",
        valid = true,
        invalid = false,
        validated = true
    },
    password = {
        unvalidated = false,
        value = "qwerty123",
        input = "qwerty123",
        name = "password",
        valid = true,
        invalid = false,
        validated = true
    },
    password2 = {
        unvalidated = false,
        value = "qwerty123",
        input = "qwerty123",
        name = "password2",
        valid = true,
        invalid = false,
        validated = true
    }
}

Dies ist großartig für die weitere Verarbeitung und das Zurücksenden der Felder als JSON-codierte Daten an die clientseitige Javascript-Anwendung, aber normalerweise ist dies eine zu schwere Struktur, um sie an die Backend-Schicht zu senden. Um eine einfache Schlüssel-Wert-Tabelle zu erhalten, können wir diese Felder-Tabelle aufrufen:

local data = fields()

Die data-Variable wird jetzt enthalten:

{
    nick = "test",
    email = "[email protected]",
    email2 = "[email protected]",
    password = "qwerty123",
    password2 = "qwerty123"
}

Jetzt ist dies etwas, das Sie beispielsweise in Redis oder in welcher Datenbank (Abstraktions-)Schicht auch immer haben, senden können. Aber das hört hier nicht auf, wenn Ihre Datenbankschicht nur an nick, email und password interessiert ist (z.B. diese Duplikate entfernen), können Sie sogar die data-Tabelle aufrufen:

local realdata = data("nick", "email", "password")

Die realdata wird jetzt enthalten:

{
    nick = "test",
    email = "[email protected]",
    password = "qwerty123"
}

field:accept(value)

Für das Feld können Sie accept aufrufen, das Folgendes tut:

self.error = nil
self.value = value
self.valid = true
self.invalid = false
self.validated = true
self.unvalidated = false

field:reject(error)

Für das Feld können Sie reject aufrufen, das Folgendes tut:

self.error = error
self.valid = false
self.invalid = true
self.validated = true
self.unvalidated = false

string field:state(invalid, valid, unvalidated)

Das Aufrufen von state auf einem Feld ist großartig, wenn Sie Validierungsergebnisse beispielsweise in eine HTML-Vorlage einbetten, wie lua-resty-template. Hier ist ein Beispiel mit lua-resty-template:

<form method="post">
    <input class="{{ form.email:state('invalid', 'valid') }}"
            name="email"
            type="text"
            placeholder="Email"
            value="{{ form.email.input }}">
    <button type="submit">Beitreten</button>
</form>

Je nach Zustand des E-Mail-Feldes wird dies eine Klasse zum Eingabeelement hinzufügen (z.B. die Grenze des Eingabefelds rot oder grün machen).

Änderungen

Die Änderungen jeder Veröffentlichung dieses Moduls sind in der Datei Changes.md aufgezeichnet.

Siehe auch

GitHub

Zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul finden Sie im GitHub-Repository für nginx-module-validation.