#php #forms
#php #формы
Вопрос:
На моем веб-сайте у меня есть учетные записи пользователей, которые настраиваются с помощью форм, которые позволяют пользователям обновлять все, от имени и фамилии до настроек конфиденциальности. Я использую следующую функцию для обновления базы данных с помощью этого ввода. (Обратите внимание, что следующий код использует специфичные для WordPress функции.)
function update_account() {
global $current_user; get_currentuserinfo();
require_once( ABSPATH . WPINC . '/registration.php' );
$uid = $current_user->ID;
// First Name
if(isset($_POST['first_name']) amp;amp; $_POST['first_name'] <> $current_user->first_name) {
wp_update_user( array(
'ID' => $uid, 'first_name' => esc_attr($_POST['first_name'])
));
}
// ...and so on 43 more times...
}
Это похоже на неправильный способ обработки форм. Также похоже, что это негативно скажется на производительности сервера при наличии нескольких пользователей и частых обновлениях, учитывая, что условия if-then-else для каждого поля, даже полей, отсутствующих на определенной странице, заставляют проверять каждое поле на ввод.
Более того, поскольку можно ожидать, что данные формы останутся относительно постоянными, я добавил оператор <>, чтобы функция не обновляла поля, в которых не было никаких изменений, но я подозреваю, что это также означает, что каждое поле по-прежнему оценивается на предмет изменений. Что еще хуже, добавление новых полей — всего их уже 44 — является громоздким процессом.
Какой лучший способ обработки данных формы?
Ответ №1:
Сохраните массив полей, которые вы будете обрабатывать с помощью этого кода, и выполните итерацию по нему. Это работает, например, если все ваши атрибуты являются строками. Если у вас есть разные типы данных, такие как логические флаги, которые обрабатываются иначе, чем строки, вы можете захотеть сгруппировать их в их собственный массив.
// All the fields you wish to process are in this array
$fields = array('first_name', 'last_name', 'others',...'others99');
// Loop over the array and process each field with the same block
foreach ($fields as $field) {
if(isset($_POST[$field]) amp;amp; $_POST[$field] != $current_user->{$field}) {
wp_update_user( array(
'ID' => $uid, $field => esc_attr($_POST[$field])
));
}
}
Комментарии:
1. О, это интересно. Я мог бы даже сгенерировать массив из базы данных, чтобы не возиться с источником. Разве это не повторяется по каждому полю, даже по не относящимся к делу полям? Может ли большой массив оказать существенное влияние на процессор или память?
2. @fireundubh Он выполняет итерации только по полям, которые вы определили в массиве. Но если они не заданы
$_POST
, они будут пропущены в цикле, так же, как вы уже сделали с вашими 44if()
операторами. Я бы не стал беспокоиться о его производительности, пока вы действительно не обнаружите, что это проблематично, а затем настройте его.3. Почему бы не отменить его и не проверить
in_array($key)
, сforeach ($_POST as $key => $val)
помощью?4. Я адаптировал ваше решение и извлек пары ключ-значение поля из базы данных. Необходимо решить некоторые проблемы SQL, связанные с безопасностью, но это другой вопрос. Спасибо.
Ответ №2:
В вашей реализации многого не хватает. Я не знаю, какими данными вы разрешаете пользователю манипулировать, но у большинства обычно есть какие-то приемлемые требования. Например, отсутствие определенных символов, отсутствие пробелов и т. Д. Я не вижу никакой проверки, так как же вы обрабатываете значения, которые могут быть нежелательными? И что происходит, когда вы получаете неверные данные? Как вы информируете пользователя о неверных данных и предлагаете им исправить это?
Если мы немного абстрагируемся от ситуации, мы можем прийти к обобщениям и реализовать соответствующее решение. В основном поля формы [могут] иметь значение по умолчанию, заданное пользователем значение [при просмотре формы], требования к проверке и ошибки проверки [с сообщениями]. Форма — это набор полей, которые при отправке формы должны быть проверены и, если они недействительны, повторно отображены пользователю с инструктивными подсказками для исправления.
Если мы создадим класс form, который инкапсулирует приведенную выше логику, мы сможем создать экземпляр и использовать его для передачи наших контроллеров / представлений. Упс, я просто предполагал, что вы используете фреймворк типа Model / View / Controller, и я не очень хорошо знаком с WordPress, поэтому я не знаю, применимо ли это в точности. Но принцип все еще применяется. На странице, где вы оба отображаете или обрабатываете форму, вот некоторая псевдологика, как это может выглядеть.
function update_account()
{
// initialize a new form class
$form = new UserAccountInfoForm();
// give the form to your view for rendering
$this->view->form = $form;
// check if form was posted [however your framework provides this check]
if(!Is_Post())
return $this->render('accountform.phtml');
// check if posted form data validates
if(!$form->isValid($_POST))
{
// if the form didn't validate re-display the form
// the view takes care of displaying errors, with the help of its
// copy of the $form object
return $this->render('accountform.phtml');
}
// form validated, so we can use the supplied values and update the db
$values = $form->getValues(); // returns an array of ['fieldname'=>'value']
// escape the values of the array
EscapeArrayValues($values);
// update db
wp_update_user($values);
// inform the user of successful update via flash message
$this->flashMessage('Successfully updated profile');
// go back to main profile page
$this->redirect('/profile');
Это делает ваш контроллер относительно чистым и простым в работе. Представление получает некоторую любовь и заботу, используя значение $form для правильного отображения формы. Технически, вы можете реализовать метод в классе form, чтобы предоставить вам форму html, но для простоты я просто предположу, что ваш HTML-код формы вручную закодирован в accountform.phtml, и он просто использует $form для получения информации о поле
<form action='post'>
<label>first name</label> <input class='<?=$this->form->getElement('first_name')->hasError() ? "invalid":""?>' type='text' name='first_name' value="<?=$this->form->getElement('first_name')->getValue()"/> <span class='errmsg'><?=$this->form->getElement('first_name')->getError()?></span><br/>
<label>last name</label> <input class='<?=$this->form->getElement('last_name')->hasError() ? "invalid":""?>' type='text' name='last_name' value="<?=$this->form->getElement('last_name')->getValue()"/> <span class='errmsg'><?=$this->form->getElement('last_name')->getError()?></span><br/>
<label>other</label> <input class='<?=$this->form->getElement('other')->hasError() ? "invalid":""?>' type='text' name='other' value="<?=$this->form->getElement('other')->getValue()"/> <span class='errmsg'><?=$this->form->getElement('other')->getError()?></span><br/>
<input type='submit' value='submit'/>
</form>
Здесь псевдокод основан на методе класса формы «getElement», который возвращает экземпляр класса field для указанного имени поля (который будет создан инициализированным в конструкторе вашего класса form). Затем в методах класса field «hasError» и «getError», чтобы проверить, правильно ли проверено поле. Если форма еще не отправлена, то они возвращают false и пустое значение, но если форма была опубликована и недействительна, то они будут соответствующим образом установлены в методе validate при его вызове. Также «GetValue» вернет либо значение, предоставленное пользователем при отправке формы, либо, если форма не была отправлена, значение по умолчанию, указанное при создании экземпляра и инициализации класса field.
Очевидно, что этот псевдокод использует много магии, которую вам придется реализовать, если вы создадите свое собственное решение — и это, безусловно, выполнимо. Однако на этом этапе я направлю вас к компонентам Zend Framework Zend_Form. Вы можете использовать компоненты zend Framework сами по себе без необходимости использовать всю структуру фреймворка и приложения. Вы также можете найти похожие решения для компонентов формы из других фреймворков, но я бы не знал о них (мы являемся магазином Zend Framework на моем рабочем месте).
Надеюсь, это не было слишком сложно, и вы знаете, что делать дальше. Конечно, просто спросите, нужны ли вам какие-либо разъяснения.