Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В. Объектно-ориентированное программирование на PHP. Авторы: Кузнецов М.В., Симдянов И.В. PHP. Практика создания Web-сайтов (второе издание). Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Обработка формы с 20-тью и более полями
 
 автор: skipper   (12.12.2013 в 15:39)   письмо автору
 
 

День добрый.

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

Приведу отрывок кода, правильно ли я обрабатываю поля формы: Пользователь нажал кнопку Submit

foreach ($_POST as $element => $value) 
    {
        if ($element != 'submit')
        {
        //проверка параметров формы с костылем
        if(!empty($value) && strlen($value)<= $max || is_numeric($value)) 
        {
            if (!is_numeric(trim($value))) $error .="$element должен принимать числовое значение<br />"; 
            if ($value<0 || $value>10) $error .="$element должен принимать значение от 0 до 10<br />";   
            $mas[$i] = clearText($value);
            $i ++;
        }
        else $error .= "$element введен неправильно или отсутствует<br />"; 
        }
    }

  Ответить  
 
 автор: psychomc   (12.12.2013 в 18:17)   письмо автору
 
   для: skipper   (12.12.2013 в 15:39)
 

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

  Ответить  
 
 автор: confirm   (12.12.2013 в 19:05)   письмо автору
 
   для: skipper   (12.12.2013 в 15:39)
 

Лучше не так. Во первых вместо if (!is_numeric(trim($value))) лучше уж тогда if((int)$value), trim для такой проверки лишнее.

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

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

<input type="number" required min="1" max="10" pattern="\b[1-9]{1}[\d]{1,2}" maxlength="2" name="rand[0]" />
<input type="number" required min="1" max="10" pattern="\b[1-9]{1}[\d]{1,2}" maxlength="2" name="rand[3]" />
<input type="number" required min="1" max="10" pattern="\b[1-9]{1}[\d]{1,2}" maxlength="2" name="rand[7]" /> 


Различные новые браузеры по разному отображают поле этого типа, удобнее всего это делает Опера и Хром (а также браузеры на движке как у Хрома), показывая в поле кнопки + - (стрелки). Не все браузеры понимают и min/max, как и паттерн им по боку, но кто-то на одно реагирует, кто-то на другое, но required (обязательное) понимают все.

Заметьте как именуются поля. То есть писать name="имя_перменной_1", name="имя_перменной_2" и т.д.., большой необходимости нет, лучше вообще давать именам полей случайные значения каждый раз при выдаче формы, и работать на сервер с индексами. При этом в примере индексы не по порядку, это к тому, чтобы было понятно, что поля в форме можно расставлять в любом порядке, а не строго один за другим согласно их индексации.

Сервер. Вообще задача проверки только на цифру была бы простая:

<?
//для одномерного массива
$val array_map('intval'$_POST['vars']);
//это будет массив полученных значений, которые не равны числам числам
//ключи сохраняются, так что указать какое поле с ошибкой не сложно
$err array_intersect($val, array(0));
//аналогично не трудно проверить и на длину, достаточно в array_map задать соответсвующее
//для многомерных массивов нужна рекурсия
array_walk_recursive($_POST['vars'], function(&$v) {
    
$v = (int)$v;
});


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

Ну и собственно проверка, вернее ее принцип:

<?
//для проверки описываем массив, определяющий проверки согласно индексам полей, например
$check = array(
    array(
'rqd'=>1'fun'=>array('myFunc1'=>1,'myFunc2'=>1), 'flt'=>FILTER_VALIDATE_REGEXP'opt'=>array('options'=>array('regexp' =>'/pattern/'))),
    array(
'rqd'=>1'flt'=>FILTER_VALIDATE_REGEXP'opt'=>array('options'=>array('regexp' =>'/pattern/'))),
    array(
'rqd'=>1'flt'=>FILTER_VALIDATE_EMAIL),
    array(
'rqd'=>0'flt'=>FILTER_VALIDATE_INT)
);
//первый ключ массива определяет обязательное поле или нет, далее указан тип проверки
//(фильтр), а также могут быть добавлены пользовательские условия проверки
//(функции, ключ fun, где прописаны имена функций и возвращаемые ими значение если проверка успешна)
//функции могу потребоваться, например или для того, чтобы перед проверкой что-то изменить
//в исходном массиве, или произвести некие манипуляции с данными

//схожие значения в массиве $check не обязательно приписывать каждому индексу проверяемому
//можно прописать раз, подставляя затем к индексам массива, например, один и тот же pattern
array('rqd'=>true'flt'=>FILTER_VALIDATE_REGEXP)+$options[1]
//где некому индексу массива $check из массива опций $options добавляется pattern для фильтра

//описываете массив содержащий различные сообщения об ошибках
//и массив описывающий текстовые именования у полей форм, в примере $fld
//сама проверка это в цикле проверять обязательное ли поле, если нет и пустое, то далее, 
//если не обязательное, но и не пустое, то проверка по условию, в простом виде, что-то такое
//ну и конечно обязательное наличие обязательных полей и их проверка

foreach($values as $k=>$v) {
    if(
array_key_exists($k$check) && $check[$k]['rqd'] && !$v) { //обязательное поле, но пустое
        
$err[$k] = getError('номер идекса ошибки в массиве сообщений об обшибках');
        continue; 
    } else {
        if(
array_key_exists($k$check) && !$check[$k]['rqd'] && !$v) continue; //если не обязательное поле и пустое
        
if(array_key_exists($k$check) && array_key_exists('fun'$check[$k])) { //индивидуальные функции
            
foreach($check[$k]['fun'] as $f=>$j) {
                if(
$f($v)) {
                    
$err[$k] = getError($j);
                    break;
                }
            }
        }
        if(
array_key_exists($k$check) && array_key_exists('flt'$check[$k]) && !isset($err[$k])) {
            if(!
filter_var($v$check[$k]['flt'], array_key_exists('opt'$check[$k]) ? $check[$k]['opt'] : null)) { //фильтр
                
$err[$k] = getError($k);
                continue;    
            } 
        } else continue;
    }
}
//если есть ошибки при проверке
if($err) {
    
array_walk($err, function(&$v$k) use($fld) {
        
//здесь обрамляем сообщения об ошибках тегами
    
});
    
//включем их в сообщение
    
$err '<p>При заполнении формы допущены ошибки в полях:</p><p>'.implode('<br>'$err).'</p>';
}        


Проверку целостности формы можно сделать следующим образом. Описываете в массиве поля формы как строку состоящую из индексов ее полей, при этом могут быть различные вариации, например, поля с индексами 0, 1, 2, 3 должны быть всегда, а с индексами 4, 5 и 6 могут быть вариации, вот все эти вариации и записываются в массиве для конкретной формы (имя формы можно всегда знать, даже если и ей давать имена случайные) - array('0123', '01234', '01235', '012345',...). А проверить так:

<?
ksort
($_POST['vars']);
if(
in_array((string)implode(array_keys($_POST['vars'])), $fields[$form_name])) {
    
//форма не нарушена   
}
//где $fields, это массив описывающий вышеуказанный массив вариаций полей формы
//$form_name - ключ этого массива, имя формы


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

  Ответить  
 
 автор: skipper   (12.12.2013 в 21:14)   письмо автору
 
   для: confirm   (12.12.2013 в 19:05)
 

confirm да, это очень удобно.

Не могли бы вы привести пример как будет выглядеть массив $values, к примеру, состоящий из 2-ух текстовых полей, обязательных, одно - числовое(патерн - проверка на число), второе - электронный адрес (патерн - проверка корректности электронного адреса).

Патерны описывать не нужно, нужно понять принцип.

  Ответить  
 
 автор: confirm   (12.12.2013 в 21:39)   письмо автору
 
   для: skipper   (12.12.2013 в 21:14)
 

Что значит как? Это будут два поля формы, а уж какие имена вы им дадите, это разве принципиально?
$values = array_values($_POST), и значения ваших двух полей будут в массиве $values под соответствующими индексами, не важно как они именовались реально. Впрочем вы можете работать и не с индексами, а с ключами, но это не совсем удобно при асинхронном обмене, если предполагается использование этого принципа на множестве форм на однотипных полях.

>состоящий из 2-ух текстовых полей, обязательных, одно - числовое(патерн - проверка на число)

Я же вам писал выше - наличие ограниченного типа полей в форме, это вчерашний день, только ленивые не пользуются новыми браузерами, ну и те кто по каким либо причинам вынужден это делать. А значит первое поле не текстовое поле, а number, а браузеры-инвалиды будут его воспринимать как type=text.

PS. Ошибку в описании заметил

(функции, ключ fun, где прописаны имена функций и возвращаемые ими значение если проверка успешна)

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

<?
if(!$f($v)) {
    
$err[$k] = getError($j);
    break;
}

  Ответить  
 
 автор: skipper   (13.12.2013 в 09:26)   письмо автору
 
   для: confirm   (12.12.2013 в 21:39)
 

Мне не очень понятно, как с учетом кода ниже будет выглядеть массив values ?

foreach($values as $k=>$v) { 
    if(array_key_exists($k, $check)



А точнее его ключи.

  Ответить  
 
 автор: confirm   (13.12.2013 в 12:43)   письмо автору
 
   для: skipper   (13.12.2013 в 09:26)
 

Как зададите, так и будут. Я вам написал пример, который строится не на ключах, а на индексах, то есть, повторяю:

если я именую поля формы случайно, то форма в некотором сеансе может иметь например такие поля

<input name=m9dd1a11ac442a5b801afb9887a2db3db[0] />
<input name=m9dd1a11ac442a5b801afb9887a2db3db[1] />
<input name=m9dd1a11ac442a5b801afb9887a2db3db[2] />


это случайное имя хранится на сервере, и при получении формы проверяется есть ли такой ключ полей формы, плюс с учетом cookie. Если есть, то что вернет функция:

<?
$values 
array_valueys[$_POST[$set_key]];
//где $set_key] равен запомненному ключу m9dd1a11ac442a5b801afb9887a2db3db


Неужели без объяснения не понятно, что переменная будет содержать массив:

[0] => XXX
[1] => XXX
[2] => XXX

А работая с ключами, то есть именами которыми вы обзываете поля формы, у вас не возникает затруднений? Вы же понимаете, что если назвали поле формы как f1, то в массив $_POST будет содержать обязательно такое: f1 => XXX. А если выбросить ключ и заменить его индексом, то что будет? То же самое, но индексный массив. Работайте с ключами, а не с индексами, разницы то практически никакой нет, для сервера, а вот для клиента, то это от ситуации.

В общем все что я выше написал, вам все понятно, а вот что такое ключи и индексы для понимания никак? )

  Ответить  
 
 автор: Jovidon   (13.12.2013 в 16:21)   письмо автору
 
   для: confirm   (13.12.2013 в 12:43)
 

капец!!!

если не секрет сколько вам лет?

  Ответить  
 
 автор: confirm   (14.12.2013 в 01:14)   письмо автору
 
   для: Jovidon   (13.12.2013 в 16:21)
 

В следусем году пойду в сталсую глупу в садике )

  Ответить  
 
 автор: skipper   (13.12.2013 в 17:15)   письмо автору
 
   для: confirm   (13.12.2013 в 12:43)
 

То есть по факту получается что количество элементов в массиве $check равно количеству полей нашей формы, которые нуждаются в обработке.

То есть имеем 21 поля для проверки и массив check будет совершать 21 элемент....

  Ответить  
 
 автор: confirm   (14.12.2013 в 00:45)   письмо автору
 
   для: skipper   (13.12.2013 в 17:15)
 

Что такое форма?
Как можно представить поля формы?
Если у вас по факту нужно принять 21 значение от пользователя, вы можете это сделать всего например 3-мя полями формы?
Если в двоичной арифметике один разряд может иметь всего лишь два состояния, можно ли одним разрядом описать 4 состояния?
Если 21 одно значение требует различных условий проверки, то можете ли вы эти 21 условие описать всего 3-мя условиями?

Получая форму с 21 значениями вы вынуждены либо в цикле писать - "такс, имечко A, а оно соответствует N?, а это имечко B, а оно соответствует M?...", или же как некоторые деятели, в лоб: if(A==N)..., if(B==M)..., и так далее, пока прокрутка не перегорит от усталости.

Вы можете утверждать, что 21 различное состояние можно описать тремя? Нет. Так к чему эти рассуждения? Вы вынуждены проверять каждое индивидуально, вопрос только в том как проверять.

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

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

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

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

Но ведь такие затраты можно избежать. Форма, это массив элементов, и как и любой другой массив эта коллекция имеет индексацию. Значит можно получить один раз коллекцию элементов формы как массив, а получать элементы формы, это всего лишь сдвигать указатель массива. Отпадает необходимость в проверке имен, проверки соответствий. Для этого достаточно осуществить проход циклом массива полученного от сервера - именно он и определит адресацию. А чтобы не было сбоев, при индексной адресации индексы полям нужно прописывать принудительно, ибо они выполняют в данном случае роль "уникального имени".

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

Зачем иметь массу серверных скриптов, которые призваны выполнять обслуживание форм клиента? Зачем иметь на клиенте массу функций отправляющих запрос серверу и обрабатывающих ответ его? Ведь всего лишь парой ключ->значение можно описать столько состояний, что Шехерезаде за 1001 и одну ночь не пересказать все. Почему не передавать единственной функции на клиенте единственный параметр, который и будет служить источником такой пары ключ->значение, и который приходя от разных источников тем не менее формируется по одному и тому же правилу для всех?

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

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

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

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

<?
echo '<pre>';

$options = array(
    array(
'set'=>10),
    array(
'set'=>20)
);

$data = array(
    array(
'fld'=>'Field 0')+$options[0],
    array(
'fld'=>'Field 1')+$options[0],
    array(
'fld'=>'Field 2')+$options[1],
    array(
'fld'=>'Field 3')+$options[0],
    array(
'fld'=>'Field 4')+$options[0],
    array(
'fld'=>'Field 5''set'=>30)
);

if(
$_POST) {
    echo 
'THE BULK OF THE INCLUSION OF OPTIONS:<br>';
    
print_r($data);
    
    
$send_values $_POST['as'];
    echo 
'INPUT:<br>';
    
print_r($send_values);
    
    
$obtain_data_on_the_keys array_intersect_key($data$send_values);
    echo 
'OBTAINED DATA ON THE ARRAY KEYS FORM:<br>';
    
print_r($obtain_data_on_the_keys);
    
    
array_walk($obtain_data_on_the_keys, function(&$v) {
         
$v implode(' -> '$v);
    });
    echo 
'RESULT OUTPUT ARRAY:<br>';
    
print_r($obtain_data_on_the_keys);
    
    echo 
'RESULT:<br>'.implode('<br>'$obtain_data_on_the_keys);
}

echo 
'</pre>';
?>

<form method="post">
<input name="as[0]" value="it does not matter, we are interested in the fields indexes" /><br />
<input name="as[1]" value="it does not matter, we are interested in the fields indexes" /><br />
<input name="as[2]" value="it does not matter, we are interested in the fields indexes" /><br />
<input name="as[5]" value="it does not matter, we are interested in the fields indexes" /><br />
<button>Send</button>
</form>


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

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

А теперь выбросите из этого примера данные и замените их ссылками на функции, объекты, и все будет работать.

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

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

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

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

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования