Эффективная проверка данных - PullRequest
1 голос
/ 17 мая 2010

Какой эффективный способ справиться с проверкой данных, скажем, с помощью отправки формы?

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

// Store errors here
$errors = array();

// Hypothetical check if a string is alphanumeric
if (!preg_match('/^[a-z\d]+$/i', $fieldvalue))
{
    $errors[$fieldname] = 'Please only use letters and numbers for your street address';
}

// etc...

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

class Validation
{
    private $errorList = array();

    public function isAlphaNumeric($string, $field, $msg = '')
    {
        if (!preg_match('/^[a-z\d]+$/i', $string))
        {
            $this->errorList[$field] = $msg;
        }
    }

    // more methods here

    public function creditCard($cardNumber, $field, $msg = '')
    {
        // Validate credit card number
    }

    // more methods here

    public function hasErrors()
    {
        return count($this->errorList);
    }
}

/* Client code */

$validate = new Validation();
$validate->isAlphaNumeric($fieldvalue1, $fieldname1, 'Please only use letters and numbers for your street address');
$validate->creditCard($fieldvalue2, $fieldname2, 'Please enter a valid credit card number');

if ($validate->hasErrors())
{
    // Handle as appropriate
}

Естественно, это не заняло много времени, прежде чем этот класс стал раздутым с фактически неограниченными типами данных, которые будут проверены.Сейчас я использую декораторы для разделения различных типов данных на их собственные классы и вызываю их только при необходимости, оставляя общие проверки (то есть isAlphaNumeric ()) в базовом классе:

class Validation
{
    private $errorList = array();

    public function isAlphaNumeric($string, $field, $msg = '')
    {
        if (!preg_match('/^[a-z\d]+$/i', $string))
        {
            $this->errorList[$field] = $msg;
        }
    }

    // more generic methods here

    public function setError($field, $msg = '')
    {
        $this->errorList[$field] = $msg;
    }

    public function hasErrors()
    {
        return count($this->errorList);
    }
}

class ValidationCreditCard
{
    protected $validate;

    public function __construct(Validation $validate)
    {
        $this->validate = $validate;
    }

    public function creditCard($cardNumber, $field, $msg = '')
    {
        // Do validation
        // ...
        // if there is an error
        $this->validate->setError($field, $msg);
    }

    // more methods here
}

/* Client code */

$validate = new Validation();
$validate->isAlphaNumeric($fieldvalue, $fieldname, 'Please only use letters and numbers for your street address');

$validateCC = new ValidationCreditCard($validate);
$validateCC->creditCard($fieldvalue2, $fieldname2, 'Please enter a valid credit card number');

if ($validate->hasErrors())
{
    // Handle as appropriate
}

AmЯ на правильном пути?Или я просто усложнил проверку данных больше, чем нужно?

Ответы [ 4 ]

2 голосов
/ 17 мая 2010

Во всяком случае, вы недостаточно проверяете. Для чтения данных в $ _POST и $ _GET вам нужно как минимум:

  • Чтобы проверить, существует ли он (array_key_exists)
  • Чтобы проверить, массив это или нет
  • Если вы ожидаете UTF-8, проверьте, действительно ли это UTF-8 (опция preg_match с модификатором 'u' является опцией)
  • Затем выполните проверку, относящуюся к типу поля

Кстати, современный способ проверки и очистки в PHP - использовать filters . В вашем конкретном случае, вот пример:

<?php
$data = array(
    "arg1good" => "sdgdf790",
    "arg1bad"  => "sdgdf7/90",
    "arg1bad2" => array("sdgdf90", "sfdssf"),
    "arg2good" => "4567576456",
    "arg2bad"  => "45675764561",
);

$validateCredCard = function ($cc) {
    if (preg_match('/^\\d{10}$/', $cc))
        return $cc;
    else
        return false;
};

$arg1filt = array('filter'  => FILTER_VALIDATE_REGEXP,
                  'flags'   => FILTER_REQUIRE_SCALAR,
                  'options' => array('regexp' => '/^[a-z\d]+$/i'),
                  );
$arg2filt = array('filter'  => FILTER_CALLBACK,
                  'flags'   => FILTER_REQUIRE_SCALAR,
                  'options' => $validateCredCard,
                  );
$args = array(
    "arg1good" => $arg1filt,
    "arg1bad"  => $arg1filt,
    "arg1bad2" => $arg1filt,
    "arg2good" => $arg2filt,
    "arg2bad"  => $arg2filt,
);

var_dump(filter_var_array($data, $args));

дает:

array(5) {
  ["arg1good"]=>
  string(8) "sdgdf790"
  ["arg1bad"]=>
  bool(false)
  ["arg1bad2"]=>
  bool(false)
  ["arg2good"]=>
  string(10) "4567576456"
  ["arg2bad"]=>
  bool(false)
}
1 голос
/ 17 мая 2010

Вам, кажется, не очень ясно о ваших целях - производительности? простота нового кода? общая ремонтопригодность?

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

C.

0 голосов
/ 18 мая 2010

@ Lo'oris Ваш ответ относительно приведения значений не является полностью полным. Пожалуйста, рассмотрите следующий пример:

$val_1 = (int)null;    // $val_1 equals 0
$val_2 = (int)false;   // $val_2 equals 0
$val_3 = (int)'';      // $val_3 equals 0
$val_4 = (int)array(); // $val_4 equals 0

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

С точки зрения функций "check_email" - вы правы, что в Интернете можно найти много реализаций, но большинство из них либо неполные, либо неправильные.

Большинство реализаций используют выражения регулярного выражения, подобные этому:

"^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$"

или этот:

"^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$"

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

Abc\@def@example.com
customer/department=shipping@example.com
!def!xyz%abc@example.com 

которые все действительны (согласно http://www.linuxjournal.com/article/9585?page=0,0).

Пожалуйста, посмотрите также: http://www.regular -expressions.info / email.html

0 голосов
/ 17 мая 2010

Это кажется мне слишком сложным.

Числовые данные: просто приведите значение $ _POST

$val=(int)$_POST["val"];

Электронные письма: есть готовые функции, которые делают это (надеюсь найти правильный).

$email=check_email($_POST["email"]) or die("Ha!");

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

Номера телефонов: ничего не делать, если он хочет дать ложный номер, он все равно это сделает.

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

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