проверка введенных данных php
Проверка данных формы с помощью PHP
В предыдущем уроке, мы получали данные от формы, а теперь мы будем проверять на корректность вводимых данных, так как если создать форму без такой проверки, то «плохие» пользователи могут навредить вашему сайту.
1. Давайте используем ту часть кода, где мы получили данные из формы:
2. Теперь нам нужно проверить переданные нам данные. Чтобы не писать один и тот же код, давайте создадим нескольно функций для проверки.
Сначала создадим функцию для очистки данных от HTML и PHP тегов:
Дальше, создадим функцию для проверки длинны строки:
3. Нам нужно «прогнать» переменные через эти функции:
Если значения не пустые (проверили с помощью функции empty ), то можно продолжать проверку дальше:
Если длинна значений переменных нас устраивает, то можем продолжать. Также, мы использовали функцию filter_var с параметром FILTER_VALIDATE_EMAIL для валидации электронного адреса.
4. Давайте добавим сообщение об успешности операции, если данные прошли все проверки.
5. В конце, нам нужно добавить сообщения для уведомления о том, что данные не прошли проверку.
Если все произошло успешно, то мы увидим сообщение «Спасибо за сообщение»
Эта проверка не идеальна, так как не указывает на поля, которые заполнены не правильно, также сообщения об ошибках очень общие
Проверка (валидация) форм PHP
В этой главе будет показано, как обрабатывать формы PHP с учетом требований безопасности. Правильная валидация данных формы важна для её защиты от хакеров и спамеров!
Что такое валидация?
Валидация означает проверку данных, вводимых пользователем. В PHP доступны два типа проверки:
Валидация на стороне клиента — проверка выполняется на стороне клиента в веб-браузере.
Валидация на стороне сервера — после отправки данных на сервер их проверка осуществляется на серверной стороне.
Ниже приведена HTML-форма, которая содержит различные поля ввода: обязательные (required) и необязательные текстовые поля, переключатели (радио-кнопки) и кнопку отправки (submit). С этой формой мы будем с вами работать в этой главе. Попробуйте ввести данные:
Некоторые из правил проверки нашей формы:
Поле формы | Правила валидации |
---|---|
Имя | Обязатеьно для заполнения + Должно содержать только буквы и пробелы |
Обязатеьно для заполнения + Требуются символ собачка (@) и точка (.) | |
Веб-сайт | Необязательно для заполнения. Проверяется наличие валидного URL |
Комментарий | Необязательно для заполнения. Многострочное поле ввода (текстовое поле) |
Образование | Обязатеьно для заполнения + Должна быть выбрана хотя бы одна кнопка |
Текстовые поля
Поля для ввода имени, адреса электронной почты и веб-сайта создается с помощью элемента (от англ. input — ввод) с атрибутом type=»text», а поле для комментария применяется элемент
Радио-кнопки
В нашей форме выбор образования осуществляется с помощью элементов типа radio (переключатели), которые используют принцип логического «ИЛИ», позволяя выбрать только одно из нескольких значений: если вы выбираете одно положение, то все остальные становятся неактивными:
Элемент формы (form)
Главным для элемента является атрибут action, который указывает обработчик данных для формы. Обработчик данных — это файл, описывающий, что нужно делать с данными формы. Данные формы отправляются с помощью method = «post»:
$_SERVER [«PHP_SELF»] — это суперглобальная переменная, которая возвращает имя файла текущего выполняемого скрипта-обработчика.
Функция htmlspecialchars() преобразует данные, введенные пользователем, которые могут содержать нежелательные HTML-тэги. Производятся следующие преобразования:
‘&’ (амперсанд) преобразуется в ‘&’
‘ ‘ (знак «больше чем») преобразуется в ‘>’
Эти манипуляции предотвращает использование злоумышленниками кода путем внедрения скрипта (атаки с межсайтовым скриптингом) в формы.
Примечание о безопасности форм PHP
Если Вы используете на странице сайта PHP_SELF, то пользователь может ввести в адресной строке косую черту (/), а затем выполнить несколько команд межсайтового скриптинга (XSS).
Примечание: XSS (англ. Cross-Site Scripting — «межсайтовый скриптинг») — тип атаки на веб-системы, заключающийся во внедрении в выдаваемую веб-системой страницу вредоносного кода (который будет выполнен на компьютере пользователя при открытии им этой страницы) и взаимодействии этого кода с веб-сервером злоумышленника. XSS позволяет злоумышленникам внедрять клиентские скрипты в веб-страницы, просматриваемые другими пользователями..
Предположим, у нас есть следующая форма на странице с именем «send_form.php»:
Теперь, если пользователь вводит обычный URL-адрес в адресной строке, например «http://site_name.com/send_form.php», приведенный выше код будет преобразован в:
Теперь пользователь вводит URL-адрес в адресной строке и после косой черты несколько команд межсайтового скриптинга:
После таких манипуляция приведенный выше код будет переведен на:
Валидировали, валидировали… и вывалидировали! Сравниваем валидаторы данных в PHP
Изображение взято с сайта Michiana Stransportation (Bike Shops)
Если вы еще не в курсе, что такое Kontrolio, предлагаю прочесть первую часть — «Держите свои данные под контролем». Вкратце, это моя библиотека для валидации данных, написанная на PHP.
В предыдущей статье я обещал написать сравнение своей собственной библиотеки с другими имеющимися решениями, так что сегодня мы рассмотрим валидацию с помощью Aura.Filter, Respect Validation, Sirius Validation и Valitron.
Давайте представим, что у нас в разработке есть некий публичный сервис, который предполагает регистрацию пользователей для полного доступа ко всем функциям. Таким образом, форма регистрации будет содержать следующие поля:
Итак, у нас пять полей, которые пользователь должен заполнить, чтобы зарегистрироваться в нашем воображаемом сервисе. Давайте представим, что нам на вход поступили полностью невалидные данные:
Aura.Filter
Валидация с использованием Aura.Filter начинается с фабрики фильтров. Нам необходимо создать так называемый «фильтр субъекта», так как мы будет валидировать массив, а не индивидуальное значение.
Определяем правила
Как видите, описание правил достаточно простое. Aura.Filter предоставляет целый набор полезных правил «из коробки» и некоторые из них были использованы в примере выше:
The second step is to let the filter factory know about our new rule. It’s done by passing the first argument as an array of rules to the filter factory:
Следущий шаг — уведомить Aura.Filter о том, что мы создали новое правило и хотим его использовать. Это делается с помощью передачи массива правил в первый аргумент фабрики:
Теперь наше правило two_words может быть использовано так же, как и любое другое правило из стандартной поставки.
Обратная связь
Как вы помните, входящие данные, которые мы валидируем, — полностью невалидны, потому что каждое поле содержит некорректное значение или не содержит его вовсе. Поэтому предполагается, что в результате валидации мы получим ошибки и соответствующие сообщения о них.
Валидируем с Aura.Filter мы следующим образом:
В $messages записывается массив, поэтому для вывода сообщений нам потребуется два вложенных foreach:
Respect Validation
Вторая библиотека, использованная мной в сравнении, — относительно популярное решение под названием Respect Validation. Раз люди ей доверяют, думаю, там есть что посмотреть.
Для чистоты эксперимента при сравнении библиотек мы будем использовать один и тот же набор данных, определенный в начале:
Определяем правила
Как и в случае с Aura.Filter, нам необходимо собственное правило валидации для имени пользователя, поэтому давайте с него и начнем:
Внешнее API правил практически идентично Aura.Filter, только используется метод validate() вместо магии __invoke(). Мне оно, это API, показалось более простым и понятным. Ну, и к Kontrolio оно ближе 🙂
В документации я не нашел об этом упоминания, тем не менее помимо самого правила для него необходимо создать собственный тип исключения. Название класса исключения должно состоять из имени класса правила и постфикса Exception.
Ну и наконец-то мы можем провалидировать наши данные. Для начала мы передаем валидатору наше новое правило, чтобы он узнал о нем, и мы смогли его использовать в дальнейшем. В Respect Validation это делается вызовом метода with() с передачей пространства имен, в котором находятся нестандартные правила.
Теперь все нестандартные правила, находящиеся в пространстве имен MyNamespace, будут «опознаны» валидатором. Следующий шаг — описать необходимые правила и выполнить валидацию.
Обратите внимание на то, как мы применяем наше правило к атрибуту name. Здесь название класса правило трансформировалось в название метода валидатора. Остальные правила, в общем-то, интуитивно понятны.
Отдельно стоит сказать о том, зачем мы приводим массив $data к объекту. Дело в том, что Respect Validation принимает на вход объекты, а не массивы. Это следует учесть при разработке с использованием данной библиотеки.
Обратная связь
В отличие от Aura.Filter валидатор Respect выбрасывает исключение, когда валидация провалена. И в этом исключении содержатся сообщения об ошибках валидации. Поэтому пример, который только что был показан, должен быть записан следующим образом:
Используя getMessages(), мы получим плоский массив всех сообщений, который валидатор собрал в процессе валидации. Задампив массив, мы получим примерно такой результат:
Можно поменять сообщения на свои собственные. Возможно, я как-то не так понял эту библиотеку, но мне этот процесс не показался таким уж очевидным: необходимо использовать метод findMessages() на обработанном исключении, в котором вы определяете сообщения не для атрибутов, а для правил.
Не знаю, в чем ошибка, но есть пара вещей, которые я так и не понял. Вот что мы получим, определив правила вышеуказанным способом:
Как видите, сообщение для поля электронной почты не применилось, осталось стандартное. А вот сообщение за индексом 4 наоборот! И это при том, что я использовал не название правила, а название поля. В то время как если бы я использовал название правила (trueVal), моё сообщение бы куда-то затерялось. Комментарии опытных пользователей данной библиотеки очень приветствуются.
Sirius Validation
Ок, давайте перейдем к следующей библиотеке и посмотрим, как она справится со схожими задачами.
Определяем правила
И снова нам необходимо определить правило для имени пользователя. Мы его напишем как-то так:
Обратите внимание на разницу в подходах в сравнении с уже рассмотренными библиотеками. Мы определяем два вида сообщений в константах, нежели используя свойства, методы или аргументы правила.
Теперь давайте опишем логику валидации:
Как видите, набор правил весьма прост и читабелен. Для описания мы используем названия, разделенные горизонтальными черточками. Этот подход похож на тот, что используется в Laravel и Kontrolio.
Четвертый аргумент метода add() описывает сообщение об ошибке валидации, которое Sirius использует, если валидация будет провалена. А почему же мы не добавили сообщение для нашего нового правила UserNameRule?
Так это потому, что сообщения уже описаны в константах класса:
Другой вариант — использовать метод addMessage() самого валидатора:
Обратите внимание, что кастомные правила идентифицируются по полному названию их класса, в то время как в Kontrolio можно задать псевдоним/алиас.
Обратная связь
Чтобы выполнить валидацию, мы вызываем метод валидатора validate(), передавая в него данные:
В отличие от Respect, Sirius не выкинет исключение, а просто вернет false. Сообщения об ошибках валидации можно получить через метод валидатора getMessages(). Он возвращает ошибки, сгруппированные по атрибутам, так что для прохода по ошибкам нам понадобится два цикла foreach:
Valitron
Поехали дальше. Еще одно интересное решение — Valitron. Valitron отличается от остальных реализацией добавления и описания правил валидации.
Определяем правила
Первое отличие: чтобы добавить новое правило, не нужно создавать отдельный класс. Можно просто использовать замыкание, возвращающее булевский результат.
Для добавления кастомных правил в Valitron есть статический метод addRule(), в котором первые два аргумента обязательны, а третий — по желанию. Мне понравился такой способ, так как тут сразу в одном месте указывается идентификатор правила, логика и сообщение об ошибке.
Второе отличие — то, как правила применяются к атрибутам. Во всех предыдущих случаях мы видели, что атрибут — вещь как бы первичная.
В Valitron пошли другим путем и на первое место поставили именно правила валидации. Описывая правила, вы как бы применяете атрибуты к этим правилам, а не наоборот.
Valitron (как и другие решения, которые мы успели рассмотреть) предоставляет стандартные сообщения об ошибках. Если вы просто воспользуетесь ими, то увидите, что каждое сообщение начинается с названия соответствующего атрибута.
Valitron подставляет имена атрибутов в текст сообщения даже в том случае, когда используются нестандартные сообщения об ошибках. Поэтому мы и воспользовались методом label() с пустой строкой, чтобы убрать имя атрибута.
Обратная связь
Конкретно что касается валидации, API библиотеки Valitron практически ничем не отличается от того, что мы уже видели в статье. Чтобы выполнить валидацию мы вызываем метод валидатора validate():
Сообщения об ошибках валидации можно получить с помощью метода getErrors():
Сообщения здесь группирутся по атрибутам точно так же, как и в Sirius Validation, за исключеним того, что для сообщения нет отдельного класса, и мы получаем обычный многомерный массив.
Kontrolio
Ну и наконец, последняя библиотека на сегодня — моя собственная разработка под названием Kontrolio.
Определяем правила
Снова, в пятый раз мы создадим правило валидации для имени пользователя. Всё относительно просто и стандартно:
Теперь мы создаем фабрику и регистриуем правило в ней, используя метод extend():
Мы описали правила, используя синтаксис, схожий с тем, что используется в Laravel, хотя могли использовать и более многословный вариант:
Обратная связь
Валидация запускается всё тем же методом validate():
Теперь мы можем получить сообщения об ошибках, используя один из методов getErrors() или getErrorsList(). Первый метод позволяет сделать более сложный вывод ошибок, тогда как второй возвращает плоский массив. Используя getErrors() мы можем вывести сообщения как-то так:
А с getErrorsList() можно сделать более простой список сообщений:
В данной статье я показал примеры использования следующих библиотек:
«Пример из реального мира» может показаться слишком простым. Я вынужден согласиться, так как, действительно, некоторые возможности библиотек остались за бортом статьи. В принципе, если вам это будет интересно, вы можете изучить их особенности самостоятельно.
Каждая из библиотек предлагает свои фишки, имеет свои тёмные стороны, так что я думаю, что это дело вкуса и задачи — выбрать ту самую.
Благодарю за прочтение. Сделайте правильный выбор.
Фильтрация и проверка данных PHP. Частые ошибки
Материал предназначен в основном для начинающих веб-программистов.
Введение.
Часто ко мне обращаются клиенты, у которых установлены самописные CMS или модули, написанные начинающими веб-программистами, которые не понимают, что нужно для защиты данных и зачастую копируют функции фильтрации, не задумываясь о том как они работают и что именно нужно с ними делать.
Здесь я постараюсь описать как можно подробнее частые ошибки при фильтрации данных в PHP скрипте и дать простые советы как правильно выполнить фильтрацию данных.
В сети много статей по поводу фильтрации данных, но они как правильно не полные и без подробные примеров.
Разбор полетов.
Фильтрация. Ошибка №1
Для числовых переменных используется такая проверка:
Почему она приведет к SQL инъекции? Дело в том, что пользователь может указать в переменной input_number значение:
В таком случаи проверка будет успешно пройдена, т.к. функция intval получает целочисленное значение переменной, т.е. 1, но в самой переменной $number ничего не изменилось, поэтому весь вредоносный код будет передан в SQL запрос.
Правильная фильтрация:
Конечно, условие может меняться, например если вам нужно получить только определенный диапазон:
Если вы используете чекбоксы или мультиселекты с числовыми значениями, выполните такую проверку:
array_map
Так же встречаю фильтрацию в виде:
Ничего кроме улыбки это не может вызвать 🙂
Фильтрация. Ошибка №2.
Для стринг-переменных используется такая фильтрация:
Функция addslashes экранирует спец. символы, но она не учитывает кодировку БД и возможен обход фильтрации. Не стану копировать текст автора, который описал данную уязвимость и дам просто ссылку Chris Shiflett (перевод можно поискать в рунете).
Если вы не предполагаете вхождение html тегов, то лучше всего сделать такую фильтрацию:
strip_tags — убирает html теги.
htmlspecialchars — преобразует спец. символы в html сущности.
Так вы защитите себя от XSS атаки, помимо SQL инъекции.
Если же вам нужны html теги, но только как для вывода исходного кода, то достаточно использовать:
Если вам важно, чтобы значение переменной не было пустой, то используйте функцию trim, пример:
Фильтрация. Ошибка №3.
Она касается поиска в БД.
Для поиска по числам используйте фильтрацию, описанную в первой ошибке.
Для поиска по тексту используйте фильтрацию, описанную во второй ошибке, но с оговорками.
Для того, чтобы пользователь не смог выполнить логическую ошибку, нужно удалять или экранировать спец. символы SQL.
Пример без доп. обработки строки:
На выходе у нас получится запрос вида:
Это значительно увеличит нагрузку на базу.
В своём скрипте я использую функцию, которая удаляет нежелательные мне символы из поиска:
Конечно, не все из выше перечисленных символов представляют опасность, но в моём случаи они не нужны, поэтому выполняю поиск и замену.
Пример использования фильтрации:
Также советую сделать ограничение по количеству символов в поиске, хотя бы не меньше 3-х, т.к. если у вас будет большое количество записей в базе, то поиск по 1-2 символам будет значительно увеличивать нагрузку на БД.
Фильтрация. Ошибка №4.
Не фильтруются значения в переменной $_COOKIE. Некоторые думаю, что раз эту переменную нельзя передать через форму, то это гарантия безопасности.
Данную переменную очень легко подделать любым браузером, отредактировав куки сайта.
Например, в одной известной CMS была проверка, используемого шаблона сайта:
В данном случаи можно подменить значение переменной $_COOKIE[‘skin’] и вызвать ошибку, в результате которой вы увидите абсолютный путь до папки сайта.
Если вы используете значение куков для сохранения в базу, то используйте одну из выше описанных фильтраций, тоже касается и переменной $_SERVER.
Фильтрация. Ошибка №5.
В PHP скрипте переменная $group будет равна 5, если в скрипте она не была объявлена со значением по умолчанию.
Фильтрация. Ошибка №6.
Проверка. Ошибка №1.
Сталкивался со случаями, когда для AJAX запроса (например: повышение репутации) передавалось имя пользователя или его ID (кому повышается репутация), но в самом PHP не было проверки на существование такого пользователя.
Например:
Получается мы создаем запись в базе, которая совершенно бесполезна нам.
Проверка. Ошибка №2.
При выполнении различного рода действий (добавление, редактирование, удаление) с данными не забывайте проверять права пользователя на доступ к данной функции и дополнительные возможности (использование html тегов или возможность опубликовать материал без проверки).
Давно исправлял в одном модуле форума подобную ошибку, когда любой пользователь мог отредактировать сообщение администрации.
Проверка. Ошибка №3.
При использовании нескольких php файлов сделайте простую проверку.
В файле index.php (или в любом другом главном файле) напишите такую строчку перед подключением других php файлов:
В начале других php файлов напишите:
Так вы ограничите доступ к файлам.
Проверка. Ошибка №4.
Используйте хеши для пользователей. Это поможет предотвратить вызов той или иной функции путём XSS.
Пример составления хеша для пользователей:
Далее во все важные формы подставляйте инпут со значением текущего хеша пользователя:
Во время выполнения скрипта осуществляйте проверку:
Проверка. Ошибка №5.
При выводе SQL ошибок сделайте простое ограничение к доступу информации. Например задайте пароль для GET переменной:
Это позволит скрыть от хакера информацию, которая может ему помочь во взломе сайта.
Проверка. Ошибка №5.
Старайтесь не подключать файлы, получая имена файлов извне.
Например:
В таком случаи вы предотвратите подключение файлов, которые не были вами предусмотрены.
Совет.
Для большей надежности используйте один из готовых и популярных классов для фильтрации данных, дабы самому не пропустить какие-то вредоносные символы/данные. Также в этих классах часто имеется возможность выбора фильтра данных.
UPD: Поправил пост. Перенес все советы по поводу функций и переменных, которые были в комментариях.
Проверка данных с помощью PHP фильтров
Валидация данных является неотъемлемой частью работы с формами. Не только недопустимые отправленные данные могут привести к проблемам безопасности, но также могут сломать вашу веб-страницу. Сегодня мы рассмотрим, как удалить недопустимые символы и проверить данные с помощью функции «filter_var».
Большинство людей склонны думать о валидации данных как о чрезвычайно утомительном процессе, где нужно:
Есть очевидные проблемы с перечисленным выше:
filter_var в действии
filter_var будет делать, оба действия, и санитизировать и проверять данные. В чем разница между ними?
Примечание: зачем санитизировать, а не просто проверять? Возможно, пользователь случайно набрал неправильный символ или, возможно, ошибка была из-за плохих копирования и вставки. Очищая данные, вы берете на себя ответственность за ошибку пользователя.
Как использовать filter_var
Использование filter_var невероятно просто. Это просто функция PHP, которая принимает две части данных:
Например, приведенный ниже код удалит все теги HTML из строки:
Пример санитизации
Ниже приведен краткий пример очищения входных данных из двух полей: поля электронной почты и поля домашней страницы. В этом примере будут удалены любые символы, которые не должны встречаться в любом типе данных.
Пример валидации
Просто потому, что данные очищены, не гарантируется, что они правильно отформатированы. В приведенном ниже примере данные не нуждались в санитизации, но очевидно, что вход пользователя не является адресом электронной почты или URL-адресом.
Чтобы обеспечить правильное форматирование данных, их необходимо проверить.
Все вместе: Форма отправки электронной почты
Мы будем очищать и проверять все 4 части данных и отправлять их по электронной почте, только если все они корректны. Если что-либо не прошло проверку или какие-либо поля пустые, форма будет представлена пользователю вместе со списком элементов для исправления. Мы также вернем обработанные данные пользователю, если он не знает, что определенные символы являются неразрешенными.
Для первого шага просто создайте элемент формы с 5 полями: для перечисленных выше и кнопки отправки:
Вы можете проверить, была ли отправлена форма, если была установлена кнопка «Submit». Поместите следующий код над вашей формой:
Поскольку поля имени и сообщения будут очищены и проверены одинаково, мы проверем их вместе. Во-первых, проверьте, не пусто ли поле, выполнив следующие действия:
Затем очистите их, используя константу FILTER_SANITIZE_STRING
Наконец, убедитесь, что оба поля по-прежнему не пустые. Это необходимо для того, чтобы после удаления всех незаконных символов у вас не осталось пустого поля:
Мы не будем делать валидацию этих двух полей просто потому, что нет абсолютного способа проверки имени или произвольного сообщения.
Окончательный код выглядит следующим образом:
Поле электронной почты будет очищено и проверено так же, как это было ранее в уроке.
Во-первых, убедитесь, что оно не пустое:
Далее, очистите его:
Наконец, подтвердите его как истинный адрес электронной почты:
Окончательный код выглядит следующим образом:
Опять же, поле домашней страницы будет очищено и проверено так же, как ранее в уроке.
Во-первых, убедитесь, что оно не пустое:
Затем, санитизируйте его и удалите любые неразрешенные символы:
Наконец, проверьте его, чтобы убедиться, что это истинный URL:
Окончательный код выглядит следующим образом:
Теперь, когда мы проверили все поля, пришло время либо сообщить об ошибках, либо отправить сообщение. Начнем с варианта, когда ошибок не было:
Затем создаем сообщение электронной почты:
И, наконец, отправляем сообщение:
Однако, если были ошибки, сообщите об этом и попросите пользователя повторить попытку:
Завершенный проект выглядит следующим образом:
Итоги
Надеюсь, что чтение этого руководства дало вам хорошее представление о новых функциях фильтрации данных PHP. Существует еще много функций и правил, которые не были охвачены, поэтому, если вас интересует больше, обратитесь к разделу Фильтрация данных в руководстве по PHP.