Pull to refresh

Обработка заполняемой пользователем формы: как уменьшить сложность кода?

Reading time4 min
Views3.2K
Работая над написанием административного, да и пользовательского интерфейса, я не раз ловил себя на мысли — а все ли я делаю так, чтобы при минимуме усилий обеспечить оптимальное качество?

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

Программирую я на PHP, поэтому примеры серверного кода будут на этом языке.

Представим, что мы решили дополнить свой проект формой для заказа обратного звонка. Мало ли — линии часто перегружены, клиент хочет почувствовать свою весомость, мода такая… ну в общем надо. Быстро накидываем простейший html, пишем обработчик — данные красиво легли в базу, в общем — практически готово. Осталось сделать самую малость — написать обработку ошибок. (Конечно, порядок разработки весьма условен). Каким образом можно это проверить введенную пользователем информацию на правильность и уведомить его о результате?

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

Рассмотрим базовую обработку ошибок (считаем что пользовательские данные уже прошли основные проверки и фильтрации):

<?php

$errors = array();

if ( empty($person) || empty($phone) || empty($question) )
{
	$errors[] = 'Не заполнены обязательные поля';
}

if ( count($errors) )
{
	$template->assign_switch('errors', 1);

	$template->vars(array(
		'ERRORS' => implode(' ', $errors),
		'PERSON' => $person,
		'PHONE' => $phone,
		'QUESTION' => $question
		)
	);

	$template->send();
}
?>


Нам хочется привнести некоторые удобства для клиента. И на помощь нам приходит…

JavaScript

<script language="text/javascript">
<!-- //
function form_submit()
{
	if  (
		( document.forms['callback'].person.value == '' ) ||
		( document.forms['callback'].phone.value == '' ) ||
		( document.forms['callback'].question.value == '' )
	)
	{
		alert('Не заполнены обязательные поля');
	}

	return;
}
// -->
</script>


Функция alert использована лишь в качестве учебного примера, по статистике часть пользователей закроет его не читая, потому что выводится оно в дизайне ОС и не воспринимается как часть веб-страницы.

Еще раз обращу внимание на то, что серверная проверка все равно необходима.

Каждый раз, когда меня просят рассказать зачем это нужно, я вспоминаю примерно год 2004, когда я, начинающий веб-разработчик, познакомился по переписке со славным парнем с Украины, бывшим тогда автором собственной CMS. Пытаясь перенимать опыт, я как-то поинтересовался у него, как он производит обработку ошибок. Выяснилось, что делает он это только при помощи JavaScript. Пришлось уже самому делиться опытом о том, что можно сохранить страницу на компьютер, подменить адрес обработчика формы и отправить данные без валидации. И если валидации не будет уже на сервере, некорректные данные будут восприняты как нормальные, а дальше все будет зависеть от логики приложения. Позже в процессе работы я часто встречал подобные уязвимости. Вывод напрашивается сам собой — если веб-приложение пишется без понимания особенностей взаимодействия браузера клиента и сервера, результат может быть разным.

Проходит время, сложность форм растет и я обращаю свой взор на следующую технологию.

AJAX

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

<?php

$errors = array();

if ( empty($person) || empty($phone) || empty($question) )
{
	$errors[] = 'Не заполнены обязательные поля';
}

$ajax = isset($_REQUEST['ajax']);

if ( count($errors) )
{
	if ( empty($ajax) )
	{
		$template->assign_switch('errors', 1);
	
		$template->vars(array(
			'ERRORS' => implode(' ', $errors),
			'PERSON' => $person,
			'PHONE' => $phone,
			'QUESTION' => $question
			)
		);

		$template->send();
	}
	else
	{
		$ajax_handler->send(array(
			'errors' => 1,
			'error_text' => implode(' ', $errors),
			)
		);
	}
}
else
{
	$ajax_handler->send(array(
		'errors' => 0,
		'error_text' => '',
		)
	);
}
?>


Далее в браузере клиента мы можем показать тот же самый алерт или вывести сообщение любым другим удобным для нас способом. Юзабилити на высоте — не требуется перезагрузка страницы, удобство дальнейшей поддержки кода тоже — вся обработка ошибок собрана в одном месте.

Вредный совет

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

<?php

if ( count($errors) )
{
	if ( empty($ajax) )
	{
		header('Location: form.php?error_code=1');
		exit();
	}
}
?>


Мы существенно упростили себе работу по дальнейшей поддержке кода, при этом сознательно отказавшись от полной поддержки устройств с отключенным JavaScript. Чем-то пришлось жертвовать в угоду собственному удобству. Но такой подход не оправдан, если упор идет на качество разработки.

Заключение

На данный момент я продолжаю экспериментировать с проверками данных. Все еще ищу идеальное решение, которое было бы еще более оптимальным. С удовольствием выслушаю критику и обсужу все аспекты различных подходов с читателями.
Tags:
Hubs:
Total votes 11: ↑4 and ↓7-3
Comments11

Articles