Skip to content

Latest commit

 

History

History
143 lines (93 loc) · 10.7 KB

File metadata and controls

143 lines (93 loc) · 10.7 KB

4.2 Проверка введенных данных

Одним из наиболее важных правил веб-разработки является то, что нельзя доверять никаким данным, поступившим из пользовательских форм. Вы должны проверять все входящие данные перед тем, как их использовать. Множество веб-сайтов было затронуто этой очень серьезной проблемой.

Существует два наиболее часто используемых способа проверить данные. Один - это проверка средствами Javascript на стороне браузера, а второй - проверка на стороне сервера. В этом разделе мы поговорим о проверке данных средствами сервера.

Поля, обязательные к заполнению

Иногда требуется, чтобы пользователь заполнил определенные поля, но он этого не делает; например, в предыдущем разделе, когда нам требовалось имя пользователя. Чтобы получить длину строки в поле и быть уверенными, что пользователь заполнил его, мы можем использовать функцию len:

if len(r.Form["username"][0])==0{
	// код, выполняемый, если поле оказалось пустым
}

r.Form обрабатывает незаполненные поля различными способами в зависимости от их типа. Для пустых текстовых полей, текстовых областей и загружаемых файлов она возвращает пустую строку; для радиокнопок и чекбоксов просто не создаются соответствующие значения. Вместо этого при попытке доступа к ним Вы получите ошибку. Поэтому для получения значений безопаснее использовать r.Form.Get(), так как эта команда всегда возвращает пустые значения. С другой стороны, r.Form.Get() может получить только одно значение за один вызов, поэтому для того, чтобы получить карту значений, нужно использовать r.Form.

Числа

Иногда значениями поля могут быть только числа. Например, Вам нужно получить возраст пользователя в целочисленном виде, т.е. 50 или 10, вместо "довольно взрослый" или "молодой человек". Если нам нужно положительное число, мы можем сначала конвертировать значение поля в тип int, а затем уже работать с ним:

getint,err:=strconv.Atoi(r.Form.Get("age"))
if err!=nil{
	// если значение не конвертируется в целое число, то было введено не целое число
}

// проверяем диапазон значений
if getint >100 {
	// слишком много
}

Другой способ проверки - это регулярные выражения:

if m, _ := regexp.MatchString("^[0-9]+$", r.Form.Get("age")); !m {
	return false
}

Хотя регулярные выражения неэффективны в плане производительности, простые регулярные выражения довольно быстры. Если Вы с ними знакомы, то их использование может быть довольно-таки удобным способом проверить данные. Имейте в виду, что Go использует RE2, что означает, что при работе с регулярными выражениями в Go поддерживаются все символы UTF-8.

Китайские символы

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

if m, _ := regexp.MatchString("^[\\x{4e00}-\\x{9fa5}]+$", r.Form.Get("realname")); !m {
	return false
}

Английские буквы

Иногда нужно, чтобы пользователь вводил только английские буквы. Предположим, нам нужно, чтобы пользователь вводил свое имя по-английски, например, astaxie, а не asta谢. Чтобы легко осуществить такую проверку, можно воспользоваться регулярными выражениями:

if m, _ := regexp.MatchString("^[a-zA-Z]+$", r.Form.Get("engname")); !m {
	return false
}

( Прим. переводчика на русский язык - для русского языка регулярка в данном случае будет выглядеть как "[А-аЯ-яЁё]+$" )

Адрес E-mail

Если Вам нужно узнать, ввел ли пользователь корректный адрес E-mail, можно использовать следующее регулярное выражение:

if m, _ := regexp.MatchString(`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`, r.Form.Get("email")); !m {
	fmt.Println("нет")
}else{
	fmt.Println("да")
}

Выпадающий список

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

Предположим, у нас есть следующий <select>:

<select name="fruit">
<option value="apple">Яблоко</option>
<option value="pear">Груша</option>
<option value="banana">Банан</option>
</select>

Для очистки вводимых данных можно использовать следующую стратегию:

slice:=[]string{"apple","pear","banana"}

for _, v := range slice {
	if v == r.Form.Get("fruit") {
    	return true
	}
}
return false

Все функции, котоые я показал выше, есть в моем open source проекте для оперирования срезами и картами: https://github.com/astaxie/beeku

Радиокнопки

Если нам нужно узнать пол пользователя, мы можем воспользоваться радиокнопками, которые будут возвращать "1" для мужчины и "2" для женщины. Однако, какой-нибудь маленький ребенок, прочитав свою первую книгу по HTTP, захочет послать Вам "3". Будет ли готова Ваша программа обработать это исключение? Как Вы увидите, для того, чтобы узнать, послано ли нам значение из нужного диапазона, мы используем тот же метод, что и для выпадающих списков:

<input type="radio" name="gender" value="1">Мужчина
<input type="radio" name="gender" value="2">Женщина

Для проверки мы используем следующий код:

slice:=[]int{1,2}

for _, v := range slice {
	if v == r.Form.Get("gender") {
    	return true
	}
}
return false

Чекбоксы

Предположим у нас имеются несколько чекбоксов для получения информации об интересах пользователя, и мы не хотим, чтобы они возвращали непредусмотренные значения.

<input type="checkbox" name="interest" value="football">Футбол
<input type="checkbox" name="interest" value="basketball">Баскетбол
<input type="checkbox" name="interest" value="tennis">Теннис

В этом случае проверка входящих данных немного отличается от того, что было с радиокнопками, так как чекбокс возвращает срез значений:

slice:=[]string{"football","basketball","tennis"}
a:=Slice_diff(r.Form["interest"],slice)
if a == nil{
	return true
}

return false 

Дата и время

Предположим, Вы хотите, чтобы пользователи вводили дату и время правильно. Для конвертирования лет, месяцев и дней в соответствующие значения типа 'time' в Go есть пакет time. С его помощью можно легко проверить введенную дату.

t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
fmt.Printf("Go запущен в %s\n", t.Local())

После того, как нам стало известно время, мы можем использовать пакет time для решения еще большего числа задач в зависимости от наших потребностей.

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

Ссылки