Перейти к содержанию

validation: Библиотека валидации (Проверка и фильтрация ввода) для Lua и nginx-module-lua

Установка

Если вы еще не подписались на репозиторий RPM, зарегистрируйтесь. Затем вы можете продолжить с следующими шагами.

CentOS/RHEL 7 или 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

Чтобы использовать эту библиотеку Lua с NGINX, убедитесь, что nginx-module-lua установлен.

Этот документ описывает lua-resty-validation v2.7, выпущенную 25 августа 2017 года.


lua-resty-validation — это расширяемая библиотека валидации и фильтрации с цепочками для Lua и OpenResty.

Hello World с 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"

-- Валидаторы могут быть повторно использованы
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"

-- Валидаторы могут выполнять фильтрацию (т.е. изменять значение, которое проверяется)
-- valid = true, s = "HELLO WORLD!"
local valid, s = validation.string.upper "hello world!"

-- Вы можете расширить библиотеку валидации своими собственными валидаторами и фильтрами...
validation.validators.capitalize = function(value)
    return true, value:gsub("^%l", string.upper)
end

-- ... и затем использовать это
local valid, e = validation.capitalize "abc" -- valid = true,  e = "Abc"

-- Вы также можете группировать валидацию нескольких значений
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("все поля группы действительны")
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

-- Вы даже можете вызвать поля, чтобы получить простую таблицу имен и значений
-- (в этом случае все `nil` также удаляются)

-- По умолчанию это возвращает только имена и значения действительных полей:
local data = fields()
local data = fields "valid"

-- Чтобы получить только имена и значения недействительных полей, вызовите:
local data = fields "invalid"

-- Чтобы получить только имена и значения проверенных полей (независимо от того, действительны ли они):
local data = fields "validated"

-- Чтобы получить только имена и значения непроверенных полей (независимо от того, действительны ли они):
local data = fields "unvalidated"

-- Чтобы получить все, вызовите:
local data = fields "all"

-- Или комбинируйте:
local data = fields("valid", "invalid")

-- На этом не останавливается. Вы также можете получить только некоторые поля по их имени.
-- Вы можете сделать это, вызвав (возвращает таблицу):
local data = data{ "artist" }

Встроенные валидаторы и фильтры

lua-resty-validation поставляется с несколькими встроенными валидаторами, и проект открыт для вкладов новых валидаторов.

Валидаторы и фильтры без аргументов

Типовые валидаторы могут использоваться для проверки типа проверяемого значения. Эти валидаторы являются валидаторами без аргументов (вызывайте их с точкой .):

  • null или ["nil"] (так как nil является зарезервированным ключевым словом в Lua)
  • boolean
  • number
  • string
  • table
  • userdata
  • func или ["function"] (так как function является зарезервированным ключевым словом в Lua)
  • callable (либо функция, либо таблица с метаметодом __call)
  • thread
  • integer
  • float
  • file (io.type(value) == 'file')

Фильтры преобразования типов:

  • tostring
  • tonumber
  • tointeger
  • toboolean

Другие фильтры:

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

Пример

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)

Валидаторы и фильтры фабрики валидации

Фабрика валидации состоит из различных валидаторов и фильтров, используемых для проверки или фильтрации значения (вызывайте их с двоеточием :):

  • type(t), проверяет, что значение является типом t (см. Типовые валидаторы)
  • nil() или ["null"](), проверяет, что тип значения равен nil
  • boolean(), проверяет, что тип значения равен boolean
  • number(), проверяет, что тип значения равен number
  • string(), проверяет, что тип значения равен string
  • table(), проверяет, что тип значения равен table
  • userdata(), проверяет, что тип значения равен userdata
  • func() или ["function"](), проверяет, что тип значения равен function
  • callable(), проверяет, что значение является вызываемым (т.е. функцией или таблицей с метаметодом __call)
  • thread(), проверяет, что тип значения равен thread
  • integer(), проверяет, что тип значения равен integer
  • float(), проверяет, что тип значения равен float
  • file(), проверяет, что тип значения равен file (io.type(value) == 'file')
  • abs(), фильтрует значение и возвращает абсолютное значение (math.abs)
  • inf(), проверяет, что значение равно inf или -inf
  • nan(), проверяет, что значение равно nan
  • finite(), проверяет, что значение не равно nan, inf или -inf
  • positive(), проверяет, что значение положительное (> 0)
  • negative(), проверяет, что значение отрицательное (< 0)
  • min(min), проверяет, что значение не меньше min (>=)
  • max(max), проверяет, что значение не больше max (<=)
  • between(min[, max = min]), проверяет, что значение находится между min и max
  • outside(min[, max = min]), проверяет, что значение не находится между min и max
  • divisible(number), проверяет, что значение делится на number
  • indivisible(number), проверяет, что значение не делится на number
  • len(min[, max = min]), проверяет, что длина значения равна min или находится между min и max (UTF-8)
  • minlen(min), проверяет, что длина значения не меньше min (UTF-8)
  • maxlen(max), проверяет, что длина значения не больше max (UTF-8)
  • equals(equal) или equal(equal), проверяет, что значение точно равно чему-то
  • unequals(equal) или unequal(equal), проверяет, что значение не равно чему-то
  • oneof(...), проверяет, что значение равно одному из предоставленных аргументов
  • noneof(...), проверяет, что значение не равно ни одному из предоставленных аргументов
  • match(pattern[, init]), проверяет, что значение соответствует (string.match) шаблону
  • unmatch(pattern[, init]), проверяет, что значение не соответствует (string.match) шаблону
  • tostring(), преобразует значение в строку
  • tonumber([base]), преобразует значение в число
  • tointeger(), преобразует значение в целое число
  • toboolean(), преобразует значение в булево (с использованием not not value)
  • tonil() или tonull(), преобразует значение в nil
  • lower(), преобразует значение в нижний регистр (поддержка UTF-8 еще не реализована)
  • upper(), преобразует значение в верхний регистр (поддержка UTF-8 еще не реализована)
  • trim([pattern]), удаляет пробелы (вы также можете использовать шаблон) слева и справа
  • ltrim([pattern]), удаляет пробелы (вы также можете использовать шаблон) слева
  • rtrim([pattern]), удаляет пробелы (вы также можете использовать шаблон) справа
  • starts(starts), проверяет, начинается ли строка с starts
  • ends(ends), проверяет, заканчивается ли строка на ends
  • reverse, переворачивает значение (строку или число) (UTF-8)
  • coalesce(...), если значение равно nil, возвращает первое ненулевое значение, переданное в качестве аргументов
  • email(), проверяет, что значение является адресом электронной почты
  • call(function), проверяет / фильтрует значение с помощью пользовательского встроенного валидатора / фильтра
  • optional([default]), останавливает валидацию, если значение пустая строка "" или nil, и возвращает true, а также либо default, либо value

Условные валидаторы фабрики валидации

Для всех валидаторов фабрики валидации существует условная версия, которая всегда возвращает true, но где вы можете заменить фактическое значение в зависимости от того, прошел ли оригинальный валидатор проверку. Эй, это проще показать, чем сказать:

local validation = require "resty.validation"

-- ok == true, value == "Да, значение равно nil"
local ok, value = validation:ifnil(
    "Да, значение равно nil",
    "Нет, вы не предоставили значение nil")(nil)

-- ok == true, value == "Нет, вы не предоставили значение nil"
local ok, value = validation:ifnil(
    "Да, значение равно nil",
    "Нет, вы не предоставили значение nil")("не nil")

-- ok == true, value == "Да, число находится между 1 и 10"
local ok, value = validation:ifbetween(1, 10,
    "Да, число находится между 1 и 10",
    "Нет, число не находится между 1 и 10")(5)

-- ok == true, value == "Нет, число не находится между 1 и 10"
local ok, value = validation:ifbetween(1, 10,
    "Да, число находится между 1 и 10",
    "Нет, число не находится между 1 и 10")(100)

Последние 2 аргумента для условных валидаторов фабрики валидации — это значения truthy и falsy. Все остальные аргументы передаются фактическому валидатору фабрики валидации.

Групповые валидаторы

lua-resty-validation в настоящее время поддерживает несколько предопределенных валидаторов:

  • compare(comparison), сравнивает два поля и устанавливает их как недействительные или действительные в зависимости от сравнения
  • requisite{ fields }, как минимум одно из обязательных полей требуется, даже если они по себе являются необязательными
  • requisites({ fields }, number), как минимум number обязательных полей требуется (по умолчанию все из них)
  • call(function), вызывает пользовательскую (или встроенную) функцию групповой валидации
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)
-- или group:requisites{ "text", "html" }
local valid, fields, errors = group{ text = "", html = "" }

group:call(function(fields)
    if fields.text.value == "hello" then
        fields.text:reject "текст не может быть 'hello'"
        fields.html:reject "поскольку текст был 'hello', это поле также недействительно"
    end
end)

Вы можете использовать обычные операторы сравнения Lua в валидаторе группы compare:

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

requisite и requisites проверяют, является ли значение поля nil или "" (пустая строка). С requisite, если все указанные поля равны nil или "", то все поля недействительны (при условии, что они не были недействительными сами по себе), и если хотя бы одно из полей действительно, то все поля действительны. requisites работает аналогично, но там вы можете определить количество полей, которые хотите, чтобы имели значение, не равное nil и не пустой строке "". Это обеспечивает условную валидацию в следующем смысле:

  1. У меня есть (два или более) поля
  2. Все они необязательные
  3. Как минимум одно / определенное количество полей должно быть заполнено, но мне не важно, какое, пока заполнено хотя бы одно / определенное количество полей

Стоп-валидаторы

Стоп-валидаторы, такие как optional, работают как обычные валидаторы, но вместо того, чтобы возвращать true или false в качестве результата валидации ИЛИ в качестве отфильтрованного значения, вы можете вернуть validation.stop. Это значение также может использоваться внутри условных валидаторов и в валидаторах, которые поддерживают значения по умолчанию. Вот как реализован валидатор optional:

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

Эти примеры примерно эквивалентны:

-- Оба возвращают: true, "default" (они останавливают обработку :minlen(10) для nil и "" входов)
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)

Фильтрация значения и установка значения в nil

Большинство валидаторов, которые не фильтруют значение, просто возвращают true или false в качестве результата. Это означает, что сейчас нет способа сигнализировать resty.validation, чтобы фактически установить значение в nil. Поэтому есть обходной путь: вы можете вернуть validation.nothing в качестве значения, и это изменит значение на nil, например, встроенный валидатор tonil фактически реализован так (псевдокод):

function()
    return true, validation.nothing
end

Пользовательские (встроенные) валидаторы и фильтры

Иногда у вас могут быть одноразовые валидаторы / фильтры, которые вы не используете в других местах, или которые вы просто хотите быстро предоставить в качестве дополнительного валидатора / фильтра для конкретного случая. Чтобы сделать это легко и просто, мы ввели метод фабрики call с lua-resty-validation 2.4. Вот пример:

validation:call(function(value)
    -- теперь проверьте / отфильтруйте значение и верните результаты
    -- здесь мы просто возвращаем false (т.е. делая валидацию неудачной)
    return false
end)("Проверьте это значение"))

(конечно, это не обязательно должна быть встроенная функция, так как в Lua все функции являются первоклассными гражданами и могут передаваться как параметры)

Расширения встроенных валидаторов

В настоящее время lua-resty-validation поддерживает два расширения или плагина, которые вы можете включить:

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

Это то, на что вы можете обратить внимание, если хотите создать собственное расширение валидатора. Если вы это сделаете и думаете, что это будет полезно и для других, не забудьте отправить ваше расширение в виде pull-запроса для включения в этот проект, большое спасибо, ;-).

Расширение resty.validation.ngx

Как следует из названия, этот набор расширений валидаторов требует OpenResty (или как минимум модуля Lua Nginx). Чтобы использовать это расширение, все, что вам нужно сделать, это:

require "resty.validation.ngx"

Это изменит адаптеры, которые оно предоставит в resty.validation, и в настоящее время это:

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

(существуют как фабричные, так и версии без аргументов)

Также есть сопоставитель regex в расширении ngx, который использует ngx.re.match, и параметризованный md5:

  • regex(regex[, options])
  • md5([bin])
Пример
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

Этот набор валидаторов и фильтров основан на отличной библиотеке luatz от @daurnimator, которая является библиотекой для манипуляции временем и датами. Чтобы использовать это расширение, все, что вам нужно сделать, это:

require "resty.validation.tz"

Это изменит адаптеры, которые оно предоставит в resty.validation, и в настоящее время это:

  • totimetable
  • totimestamp

(существуют как фабричные, так и версии без аргументов)

Фильтры totimestamp и totimetable отлично работают с HTML5 полями ввода даты и времени. Как следует из названия, totimetable возвращает timetable luatz, а totimestamp возвращает секунды с начала эпохи Unix (1970-01-01) в качестве числа Lua.

Пример
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

Этот набор валидаторов и фильтров основан на отличной библиотеке utf8rewind от Квинтена Лансу — системной библиотеки, написанной на C, предназначенной для расширения стандартных функций обработки строк с поддержкой текста, закодированного в UTF-8. Для работы требуется моя обертка LuaJIT FFI lua-resty-utf8rewind. Когда указанные требования установлены, остальное просто. Чтобы использовать это расширение, все, что вам нужно сделать, это:

require "resty.validation.utf8"

Это изменит адаптеры, которые оно предоставит в resty.validation, и в настоящее время это:

  • utf8upper
  • utf8lower
  • utf8title

(существуют как фабричные, так и версии без аргументов)

Также есть несколько фабричных валидаторов / фильтров:

  • utf8normalize(form)
  • utf8category(category)

utf8normalize нормализует ввод UTF-8 в один из этих форматов нормализации:

  • C (или NFC)
  • D (или NFD)
  • KC (или NFKC)
  • KD (или NFKD)

utf8category проверяет, что входная строка находится в одной из следующих категорий (так что вы можете подумать, что у нее есть несколько встроенных валидаторов для работы с валидацией строк UTF-8):

  • 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
Пример
require "resty.validation.utf8"
local validation = require "resty.validation"
local valid, ts = validation:utf8category("LETTER_UPPERCASE")("TEST")

Расширение resty.validation.injection

Этот набор валидаторов и фильтров основан на отличной библиотеке libinjection от Ника Гэлбрита — парсере и анализаторе токенов SQL / SQLI / XSS. Для работы требуется моя обертка LuaJIT FFI lua-resty-injection. Когда указанные требования установлены, остальное просто. Чтобы использовать это расширение, все, что вам нужно сделать, это:

require "resty.validation.injection"

Это изменит адаптеры, которые оно предоставит в resty.validation, и в настоящее время это:

  • sqli, возвращает false, если была обнаружена SQL-инъекция, в противном случае возвращает true
  • xss, возвращает false, если была обнаружена инъекция межсайтового скриптинга, в противном случае возвращает true
Пример
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

Я не собираюсь здесь подробно описывать все различные валидаторы и фильтры, так как они все следуют одной и той же логике, но я покажу несколько общих способов, как это работает.

validation._VERSION

Это поле содержит версию библиотеки валидации, например, его значение может быть "2.5" для версии 2.5 этой библиотеки.

булевы, валидация значения / ошибки...

Этот ... означает цепочку валидации. Это используется для определения одной цепочки валидатора. Длина цепочки не ограничена. Она всегда будет возвращать булево значение (действительна ли валидация или нет). Второе возвращаемое значение будет либо именем фильтра, который не вернул true в качестве результата валидации, либо отфильтрованным значением.

local v = require "resty.validation"

-- Ниже означает создать валидатор, который проверяет, что ввод является:
-- 1. строкой
-- Если это так, то удалите пробелы в начале и конце строки:
-- 2. trim
-- Затем проверьте, что длина обрезанной строки составляет как минимум 5 символов (UTF-8):
-- 3. minlen(5)
-- И если все еще все в порядке, преобразуйте эту строку в верхний регистр
-- (поддержка UTF-8 еще не реализована в upper):
-- 4. upper
local myvalidator = v.string.trim:minlen(5).upper

-- Этот пример вернет false и "minlen"
local valid, value = myvalidator(" \n\t a \t\n ")

-- Этот пример вернет true и "ABCDE"
local valid, value = myvalidator(" \n\t abcde \t\n ")

Всякий раз, когда валидатор не проходит и возвращает false, вы не должны использовать возвращаемое значение для других целей, кроме как для отчетности об ошибках. Таким образом, цепочка работает следующим образом. lua-resty-validation не будет пытаться делать что-либо, если вы укажете цепочки, которые никогда не будут использоваться, такие как:

local v = require "resty.validation"
-- Входное значение не может одновременно быть и строкой, и числом:
local myvalidator = v.string.number:max(3)
-- Но вы могли бы написать это так
-- (взять ввод как строку, попытаться преобразовать его в число и проверить, что он не больше 3):
local myvalidator = v.string.tonumber:max(3)

Как вы видите, это способ определения отдельных повторно используемых валидаторов. Вы можете, например, заранее определить свой набор основных одиночных валидаторов и сохранить его в своем собственном модуле, из которого вы можете повторно использовать ту же логику валидации в разных частях вашего приложения. Хорошая идея — начать с определения отдельных повторно используемых валидаторов, а затем использовать их в групповых валидаторах.

Например, предположим, у вас есть модуль под названием validators:

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

А теперь у вас есть функция register где-то в вашем приложении:

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
        -- ввод действителен, сделайте что-нибудь с nick, email и password
    else
        -- ввод недействителен, nick, email и password содержат причины ошибок
    end
end

Это быстро становится немного грязным, и вот почему у нас есть групповые валидаторы.

валидация.table.new([таблица валидаторов])

Эта функция — это то место, где начинается групповая валидация. Предположим, что у вас есть форма регистрации, которая запрашивает ник, электронную почту (то же самое дважды) и пароль (то же самое дважды).

Мы повторно используем одиночные валидаторы, определенные в модуле validators:

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

Теперь давайте создадим повторно используемый групповой валидатор в модуле forms:

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

-- Сначала мы создаем одиночные валидаторы для каждого поля формы
local register = v.new{
    nick      = validate.nick,
    email     = validate.email,
    email2    = validate.email,
    password  = validate.password,
    password2 = validate.password
}

-- Затем мы создаем групповые валидаторы для электронной почты и пароля:
register:compare "email    == email2"
register:compare "password == password2"

-- И наконец, мы возвращаем из этого модуля форм

return {
    register = register
}

Теперь где-то в вашем приложении у вас есть эта функция register:

local forms = require "forms"
local function register(data)
    local valid, fields, errors = forms.register(data)
    if valid then
        -- ввод действителен, сделайте что-нибудь с полями
    else
        -- ввод недействителен, сделайте что-нибудь с полями и ошибками
    end
end

-- И вы можете вызвать это так:

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

Отличная вещь в групповых валидаторах заключается в том, что вы можете закодировать в JSON таблицы полей и ошибок и вернуть их клиенту. Это может быть полезно при создании одностраничного приложения, и вам нужно сообщать об ошибках на стороне сервера клиенту. В приведенном выше примере переменная fields будет выглядеть так (переменная valid будет true, а errors будет 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
    }
}

Это отлично подходит для дальнейшей обработки и отправки полей обратно в клиентское JavaScript-приложение в закодированном формате JSON, но обычно это слишком громоздкая конструкция для отправки на уровень бэкенда. Чтобы получить простую таблицу ключ-значение, мы можем вызвать эту таблицу полей:

local data = fields()

Переменная data теперь будет содержать:

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

Теперь это то, что вы можете отправить, например, в Redis или в любой другой слой базы данных (абстракции), который у вас есть. Но, ну, на этом не останавливается, если, скажем, ваш слой базы данных интересуется только nick, email и password (например, удалите эти дубликаты), вы даже можете вызвать таблицу data:

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

Переменная realdata теперь будет содержать:

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

field:accept(value)

Для поля вы можете вызвать accept, который делает следующее:

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

field:reject(error)

Для поля вы можете вызвать reject, который делает следующее:

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

string field:state(invalid, valid, unvalidated)

Вызов state на поле отлично подходит для встраивания результатов валидации, например, в HTML-шаблон, такой как lua-resty-template. Вот пример с использованием 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">Присоединиться</button>
</form>

Таким образом, в зависимости от состояния поля электронной почты это добавит класс к элементу ввода (например, сделает границу ввода красной или зеленой).

Изменения

Изменения каждой версии этого модуля записаны в файле Changes.md.

См. также

GitHub

Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-validation.