Валидировали, валидировали… и вывалидировали! Сравниваем валидаторы данных в PHP. Валидация и очистка данных средствами PHP Безрассудный validation php

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

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

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

Немного отступления от темы:
Работа над проектами, разработка и программирование сайтов, скриптов, прочих систем занимает практически всё мое свободное время (по мимо рабочего), иными словами я занимаюсь этим делом максимально возможное количество часов в сутки. Время от времени возникает потребность в тестировании чего либо, ради забавы или просто любопытства. В итоге подобными тестируемыми лабораторными крысами становятся сайты сделанные на скорую руку, на самописных движках или на CMS древних версий. разумеется всё перечисленное страдает от криво написанного кода, нехватки котроля за данными и просто кишит различными багами. Собственно, в большинстве случаем за час моих экспериментов над такими сайтами мне удается найти несколько серьезных уязвимостей и большинство из них кроется в недостаточной валидации пришедших данных. В последнее время часто это встречается в скриптах обрабатывающих POST данные пришедших от JavaScript + Ajax.

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

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

Думаю важность валидации всем понятна. На протяжении длительно времени я писал каждый раз один и тот же кусок кода, затем использовал собственные функции проверки данных, многие из которых были весьма примитивны и как правило разбросаны в разных частях (прииклюденных) файлов. В скором я начал знакомится с PHP фреймворками Zend, CI, Kohana, в каждом из был реализован свой класс для валидации данных, которые я заимствовал для своих проектов. В конце концов я решил заточить один из классов CI под свои нужды, но оказалось, что об этом уже позаботился автор одного из блогов по программированию. Далее делюсь его трудами, а именно модифицированной библиотекой CodeIgniter.

Разберем следующий код :

Просмотр кода PHP

require_once "validator.class.php" ; $validator = new Validator() ; $validator -> set_rules ("name" , "Ваше имя" , array ("required" => , "alpha" => ) ) ; $validator -> set_rules ("email" , "Ваш email" , array ("required" => "Поле %s обязательно для заполнения" , "valid_email" => ) ) ; if ($validator -> run () ) { echo "Валидация прошла успешно" ; } else { echo $validator -> get_string_errors () ; }

Как видно из примера, первой строкой мы подключаем файл класса validator.calss.php к нашем скрипту. Далее создаем экземпляр класса и сохраняем объект в переменную $validator .
Затем используя метод $validator->set_rules($field, $label, $rules) задаем поля для валидации.

Данный метод принимает 3 параметра:

  • $field - имя поля валидации (значение атрибута name в теге )
  • $label - название поля валидации, будет подставляться в сообщения об ошибках
  • $rules - массив правил валидации, у которого в качестве ключа используется правило валидации, а в качестве значения - сообщение об ошибке для этого правила
  • После того, как все поля для валидации установлены, запускаем валидатор используя метод $validator->run() . Если валидация прошла успешно, то данный метод вернет значение TRUE , иначе, если есть хоть какие-то ошибки, вернет FALSE .

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

  • get_string_errors() — возвращает все сообщения об ошибках в виде строки
  • get_array_errors() — возвращает все сообщения в виде массива, где в качестве ключа используется имя поля, а в качестве значения - описание ошибки для этого поля.
  • form_error($field) - возвращает сообщение об ошибке для поля, переданного в качестве параметра $field
  • По умолчанию сообщения об ошибках оборачиваются в тег . Для того чтобы задать свое оформление используйте метод set_error_delimiters($prefix, $suffix) . Например так:

    Теперь сообщения об ошибках будут оборачиваться в div с классом «error»

    Как видите все очень просто.

    Просмотр кода PHP

    $validator -> set_error_delimiters (" " , " " ) ;

    Для установки правил валидации Вы можете методу set_rules($fields) передать многомерный ассоциативный массив. Давайте посмотрим на пример:

    Просмотр кода PHP

    $rules = array ( array ( "field" => "name" , "label" => "Ваше имя" , "rules" => array ( "required" => "Поле %s обязательно для заполнения" , "alpha" => "Поле %s должно содержать только буквы" ) ) , array ( "field" => "email" , "label" => "Ваш email" , "rules" => array ( "required" => "Поле %s обязательно для заполнения" , "valid_email" => "Поле %s должно содержать правильный email-адрес" ) ) ) ; $validator -> set_rules ($rules ) ;

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

    Итак, какие же правила валидации поддерживает данный класс?

    Я вынес в этот класс наиболее распространенные правила валидации, с которыми сталкивается каждый. Вот полный список этих правил:

    required Возвращает FALSE если поле не заполнено
    integer Возвращает FALSE если значение не является целым числом
    float Возвращает FALSE если значение не числового вида
    valid_url Возвращает FALSE если значения не является корректным URL адресом
    valid_email Возвращает FALSE если значения не является корректным e-mail адресом
    valid_ip Возвращает FALSE если IP-адрес не является действительным
    matches Возвращает FALSE если элемент не соответствует значению другого элемента field
    alpha Возвращает FALSE если элемент содержит не только буквы
    valid_captcha Возвращает FALSE если значение в сессии field не равно значению поля формы
    valid_date Возвращает FALSE если элемент содержит не корректную дату

    Большинство этих правил используют фильтры , которые стали доступны в PHP 5.

    При желании вы всегда можете расширить набор правил для валидации, дописав нужные функции в класс Validator.

    Для того чтобы получить обработанное значение POST данных используется метод:

    Просмотр кода PHP

    Обычно данный метод вызываетя для очистки формы, при успешной обработке формы.

    It is very essential to have the input to your form validated before taking the form submission data for further processing. When there are many fields in the form, the PHP validation script becomes too complex. Moreover, since you are doing the same or similar validation for most of the forms that you make, just too much of duplicate effort is spent on form validations.

    About this generic PHP form validation script

    This generic PHP form validator script makes it very easy to add validations to your form.

    We create and associate a set of “validation descriptors” with each element in the form. The “validation descriptor” is a string specifying the type of validation to be performed. For example, “req” means required, “alpha” means allow only alphabetic characters and so on.

    Each field in the form can have zero, one or more validations. For example, the input should not be empty, should be less than 25 chars, should be alpha-numeric, etc

    You can associate a set of validation descriptors for each input field in the form.

    Download the PHP form validation script

    You can download the PHP form validation script below:
    The zip file contains the form validation script formvalidator.php, documentation and usage samples.

    Using the PHP form validation script
  • Include formvalidator.php in your form processing script
  • require_once "formvalidator.php"
  • Create a FormValidator object and add the form validation descriptors.
  • $validator = new FormValidator(); $validator->addValidation("Name","req","Please fill in Name"); $validator->addValidation("Email","email", "The input for Email should be a valid email value"); $validator->addValidation("Email","req","Please fill in Email");

    The first argument is the name of the input field in the form. The second argument is the validation descriptor that tells the type of the validation required. The third argument is the error message to be displayed if the validation fails.

  • Validate the form by calling ValidateForm() function
  • if(!$validator->ValidateForm()) { echo "Validation Errors:"; $error_hash = $validator->GetErrors(); foreach($error_hash as $inpname => $inp_err) { echo "

    $inpname: $inp_err

    \n"; } } Example

    The example below will make the idea clearer

    Name: Email:

    Adding Custom Validation

    If you want to add a custom validation, which is not provided by the validation descriptors, you can do so. Here are the steps:

  • Create a class for the custom validation and override the DoValidate() function
  • class MyValidator extends CustomValidator { function DoValidate(&$formars,&$error_hash) { if(stristr($formars["Comments"],"http://")) { $error_hash["Comments"]="No URLs allowed in comments"; return false; } return true; } }

  • Add the custom validation object
  • $validator = new FormValidator(); $validator->addValidation("Name","req","Please fill in Name"); $validator->addValidation("Email","email", "The input for Email should be a valid email value"); $validator->addValidation("Email","req","Please fill in Email"); $custom_validator = new MyValidator(); $validator->AddCustomValidator($custom_validator);

    The custom validation function will be called automatically after other validations.

    Table of Validation Descriptors

    Here is the list of all validation descriptors:

    Validation Descriptor Usage
    req The field should not be empty
    maxlen=??? checks the length entered data to the maximum. For example, if the maximum size permitted is 25, give the validation descriptor as “maxlen=25”
    minlen=??? checks the length of the entered string to the required minimum. example “minlen=5”
    alnum Check the data if it contains any other characters other than alphabetic or numeric characters
    alnum_s Allows only alphabetic, numeric and space characters
    num Check numeric data
    alpha Check alphabetic data.
    alpha_s Check alphabetic data and allow spaces.
    email The field is an email field and verify the validity of the data.
    lt=???
    lessthan=???
    Verify the data to be less than the value passed. Valid only for numeric fields.
    example: if the value should be less than 1000 give validation description as “lt=1000”
    gt=???
    greaterthan=???
    Verify the data to be greater than the value passed. Valid only for numeric fields.
    example: if the value should be greater than 10 give validation description as “gt=10”
    regexp=??? Check with a regular expression the value should match the regular expression.
    example: “regexp=^{1,20}$” allow up to 20 alphabetic characters.
    dontselect=?? This validation descriptor is for select input items (lists) Normally, the select list boxes will have one item saying ‘Select One’. The user should select an option other than this option. If the value of this option is ‘Select One’, the validation description should be “dontselect=Select One”
    dontselectchk This validation descriptor is for check boxes. The user should not select the given check box. Provide the value of the check box instead of ??
    For example, dontselectchk=on
    shouldselchk This validation descriptor is for check boxes. The user should select the given check box. Provide the value of the check box instead of ??
    For example, shouldselchk=on
    dontselectradio This validation descriptor is for radio buttons. The user should not select the given radio button. Provide the value of the radio button instead of ??
    For example, dontselectradio=NO
    selectradio This validation descriptor is for radio buttons. The user should select the given radio button. Provide the value of the radio button instead of ??
    For example, selectradio=yes
    selmin=?? Select atleast n number of check boxes from a check box group.
    For example: selmin=3
    selone Makes a radio group mandatory. The user should select atleast one item from the radio group.
    eqelmnt=??? compare two elements in the form and make sure the values are the same For example, ‘password’ and ‘confirm password’. Replace the ??? with the name of the other input element.
    For example: eqelmnt=confirm_pwd

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

    Общее правило безопасности - не доверять никому, так что нельзя надеяться на то, что пользователи всегда будут вводить в формы правильные значения. Например, вместо ввода в поле правильного email-адреса, пользователь может ввести неверный адрес, или вообще какие-нибудь вредоносные данные.

    Когда дело доходит до валидации пользовательских данных, ее можно проводить как на стороне клиента (в веб-браузере), так и на серверной стороне.

    Ранее валидацию на стороне клиента можно было провести только с помощью JavaScript. Но все изменилось (или почти изменилось), так как с помощью HTML5 валидацию можно проводить средствами браузера, без необходимости писать сложные скрипты для валидации на JavaScript.

    Валидация форм с помощью HTML5

    HTML5 предоставляет довольно надежный механизм, основанный на следующих атрибутах тега : type , pattern и require . Благодаря этим новым атрибутам вы можете переложить некоторые функции проверки данных на плечи браузера.

    Давайте рассмотрим эти атрибуты, чтобы понять, как они могут помочь в валидации форм.

    Атрибут type

    Этот атрибут говорит, какое поле ввода отобразить для обработки данных, например, уже знакомое поле типа

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

    Попробуйте поиграться со значениями поля email в нижеприведенной демонстрации .

    Также существуют другие стандартные типы полей, вроде , и для валидации чисел, URL’ов и телефонных номеров соотвествено.

    Замечание: формат телефонного номера различается для разных стран из-за несоответствия количества цифр в телефонных номерах и разности форматов. Как результат, спецификация не определяет алгоритм проверки телефонных номеров, так что на время написания статьи данная возможность слабо поддерживается браузерами.

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

    Атрибут pattern

    Атрибут pattern , скорее всего, заставит многих фронтенд-разработчиков прыгать от радости. Этот атрибут принимает регулярное выражение (аналогичное формату регулярных выражений JavaScript), по которому будет проверяться корректность введенных в поле данных.

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

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

    Регулярные выражения (RegEX) являются мощным, кратким и гибким инструментом для сопоставления строки текста, вроде отдельных символов, слов или шаблонов символов.

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

    Давайте посмотрим на пару примеров использования регулярных выражений для валидации значения полей ввода.

    Телефонные номера

    Как упоминалось ранее, тип поля tel не полностью поддерживается браузерами из-за несоответствия форматов номеров телефонов в разных странах.

    Например, в некоторых странах формат телефонных номеров представляется в виде xxxx-xxx-xxxx , и сам телефонный номер будет что-то вроде этого: 0803-555-8205 .

    Регулярное выражение, которому соответствует данный шаблон, такое: ^\d{4}-\d{3}-\d{4}$ . В коде это можно записатьтак :

    Phone Number:

    Буквенно-цифровые значения Атрибут required

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

    Это избавляет нас от реализации проверки полей с помощью JavaScript, что может сохранить немного времени разработчикам.

    Например: или (для совместимости с XHTML)

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

    Заключение

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

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

    Не все браузеры поддерживают HTML5, и не все данные, посланные вашему скрипту, придут с вашей формы. Это значит, что перед тем, как окончательно принять данные от пользователя, необходимо проверить их корректность на стороне сервера.

    This and the next chapters show how to use PHP to validate form data.

    PHP Form Validation

    Think SECURITY when processing PHP forms!

    These pages will show how to process PHP forms with security in mind. Proper validation of form data is important to protect your form from hackers and spammers!

    The HTML form we will be working at in these chapters, contains various input fields: required and optional text fields, radio buttons, and a submit button:

    The validation rules for the form above are as follows:

    Field Validation Rules
    Name Required. + Must only contain letters and whitespace
    E-mail Required. + Must contain a valid email address (with @ and .)
    Website Optional. If present, it must contain a valid URL
    Comment Optional. Multi-line input field (textarea)
    Gender Required. Must select one

    First we will look at the plain HTML code for the form:

    Text Fields

    The name, email, and website fields are text input elements, and the comment field is a textarea. The HTML code looks like this:

    Name:
    E-mail:
    Website:
    Comment:

    Radio Buttons

    The gender fields are radio buttons and the HTML code looks like this:

    Gender:
    Female
    Male
    Other

    The Form Element

    The HTML code of the form looks like this:



    Loading...Loading...