CodeIgniter + AJAX. Проверка данных форм без перезагрузки страниц

Владимир | | Ajax, CodeIgniter, PHP.

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

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

Давайте немного порассуждаем. Чем отличается ajax запрос от обычного запроса?

1) Ajax запрос можно выполнить только с помощью JavaScript.

2) Ответом сервера на обычный запрос должна быть html страница, а на ajax запрос – фрагмент данных (с разметкой или без нее).

Отсюда вывод. Чтобы добавить поддержку ajax нужно в клиентской части написать JavaScript функцию, которая прочтет данные из формы, отправит запрос и обработает ответ сервера, а в серверной части – изменить возвращаемые значения.

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

Переходим к нашему примеру. Как вы помните, в прошлый раз мы создали форму с тремя полями для ввода личных данных пользователя (ник, полное имя, адрес email).

В этот раз мы используем эту же форму, только немного изменим html разметку.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ru">
<head>
<title>Проверка введенных данных</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="<?php echo base_url(); ?>prototype.js"></script>
<script type="text/javascript" src="<?php echo base_url(); ?>scripts.js"></script>
</head>

<body>
<?php echo form_open('#'); ?>
<div id="status"></div>
<div id="nic_err"></div>
<p>Ник: <input type="text" name="usernic" id="usernic" value="" /></p>
<div id="name_err"></div>
<p>Полное имя: <input type="text" name="fullname" id="fullname" value="" /></p>
<div id="email_err"></div>
<p>eMail: <input type="text" name="usermail" id="usermail" value="" /></p>
<p><input type="button" id="sendbtn" value="Отправить" onclick="sendData(<?php echo "'".base_url()."'"; ?>)" /></p>
</form>
</body>
</html>

Прежде всего, перед каждым полем мы добавили блоки для отображения сообщений об ошибках (теги <div> в строках …). Сами сообщения мы будет вставлять с помощью JS.

Второе изменение коснулось кнопки «Отправить». Теперь она имеет тип button, а не submit и обработчик события onclick, который вызывает функцию отправки данных (sendData).

Сама функция sendData находится в файле scripts.js, который мы подключили в заголовке страницы вместе с библиотекой prototype (строки 6, 7).

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

С отправкой данных все довольно просто. Нужно сформировать строку с параметрами обычного POST запроса.

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

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

Примечание. Подробнее почитать об этом формате можно в статье «Передача данных с помощью JSON».

Главное преимущество заключается в том, что и JavaScript и PHP содержат функции для преобразования данных в этот формат и обратно.

Таким образом, наша функция sendData будет примет такой вид.

function sendData(baseURL) {
	//читаем данные из формы
	var n = $('usernic').value;
	var fn = $('fullname').value;
	var e = $('usermail').value;
	//формируем строку с параметрами запроса
	var pars = $H({usernic:n, fullname:fn, usermail:e}).toQueryString();
	//отправляем ajax запрос
	new Ajax.Request(baseURL + "index.php/main/checkdata_ajax",
		{method:"post", parameters:pars, onSuccess:parseResponse});
}

В параметре функции мы передаем адрес сервера. А в строках с 3-7 мы формируем строку с параметрами.

После этого мы отправляем запрос. Ответ сервера передается функции parseResponse, которая указана в параметре onSuccess запроса.

Теперь рассмотрим функцию parseResponse.

function parseResponse(transport) {
	var data = eval('(' + transport.responseText + ')');
	//ошибок не было
	if (data.status == "OK") {
		$('status').innerHTML = "Данные сохранены";
		//убираем сообщение об ошибках, если они остались после
		//предыдущей попытки
		$('nic_err').innerHTML = "";
		$('name_err').innerHTML = "";
		$('email_err').innerHTML = "";
	}
	//ошибки были, показываем их описание
	else {
		$('status').innerHTML = "Пожалуйста, проверьте введенные данные";
		$('nic_err').innerHTML = data.nic_err;
		$('name_err').innerHTML = data.name_err;
		$('email_err').innerHTML = data.email_err;
	}
}

Во второй строке мы преобразуем строку в формате JSON в структуру данных с именем data (с помощью функции eval).

Наша структура данных имеет такие поля:
status – результат обработки (может принимать два значения: «OK» и «ERR»);
nic_err – описание ошибки в поле «ник»;
name_err – описание ошибки в поле «полное имя»;
email_err – описание ошибки в поле «email».

В строке 4 мы проверяем поле data.status и в зависимости от результатов либо вставляем описание ошибок, либо убираем их.

Теперь рассмотрим серверный скрипт (checkdata_ajax), который должен находится внутри контроллера (main.php).

function checkdata_ajax() {
	$this->load->library('validation');

	$rules['usernic'] = "required|min_length[3]|checknic";
	$rules['fullname'] = "required";
	$rules['usermail'] = "required|valid_email";

	$this->validation->set_rules($rules);

	$fields['usernic'] = "ник";
	$fields['fullname'] = "полное имя";
	$fields['usermail'] = "адрес email";

	$this->validation->set_fields($fields);

	if ($this->validation->run() == TRUE) {
		//сохраняем введенные данные (например, в БД)
		//..........
		//отправляем браузеру результаты обработки
		$res['status'] = "OK";
	}
	else {
		$res['status'] = "ERR";
		$res['nic_err'] = $this->validation->usernic_error;
		$res['name_err'] = $this->validation->fullname_error;
		$res['email_err'] = $this->validation->usermail_error;
	}
	echo json_encode($res);
}

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

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

Примечание. На основе имен ключей в массиве будет создаваться структура данных в функции parseResponse.

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

  • в таком раскладе сильно смущает function checkdata_ajax() в контроллере — что будет если пользователь пойдёт по урл этого экшена?

    • Получит ответ от сервера (в формате JSON) 🙂
      Firefox показал их в таком виде:
      {«status»:»ERR»,»nic_err»:»»,»name_err»:»»,»email_err»:»»}

      В общем, что и следовало ожидать.

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

  • в таком раскладе сильно смущает function checkdata_ajax() в контроллере — что будет если пользователь пойдёт по урл этого экшена?

    • Получит ответ от сервера (в формате JSON) 🙂
      Firefox показал их в таком виде:
      {«status»:»ERR»,»nic_err»:»»,»name_err»:»»,»email_err»:»»}

      В общем, что и следовало ожидать.

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

  • Ещё было бы пару фраз о сравнении ajax-фреймворков (или скорее библиотек будет правильней сказать) — было бы вообще отлично. Хотя это темы для отдельных статей, коих в принципе и так хватает в Интернете 😎

    • Сложно не согласиться 🙂
      Сравнение ajax-фрэймворков — тема бесконечная, особенно если учесть, что они постоянно развиваются.

      По-моему, в сложившейся ситуации важнее навыки работы с конкретным фрэймворком.

    • Сравнение фреймворков видел здесь:
      http://blog.sribna.com/o-proizvoditelnosti-javascript-frameworks.htm

      Сам пока ещё не выбрал, т.к. нужно учитывать не только скорость.

      • Спасибо за ссылку, но я ее уже читал 🙂
        И вы абсолютно правы в том, что ориентироваться не только на скорость.
        Но, тем не менее, разница в скорости между prototype и dojo заставляет задуматься.

  • Ещё было бы пару фраз о сравнении ajax-фреймворков (или скорее библиотек будет правильней сказать) — было бы вообще отлично. Хотя это темы для отдельных статей, коих в принципе и так хватает в Интернете 😎

    • Сложно не согласиться 🙂
      Сравнение ajax-фрэймворков — тема бесконечная, особенно если учесть, что они постоянно развиваются.

      По-моему, в сложившейся ситуации важнее навыки работы с конкретным фрэймворком.

    • Сравнение фреймворков видел здесь:
      http://blog.sribna.com/o-proizvoditelnosti-javascript-frameworks.htm

      Сам пока ещё не выбрал, т.к. нужно учитывать не только скорость.

      • Спасибо за ссылку, но я ее уже читал 🙂
        И вы абсолютно правы в том, что ориентироваться не только на скорость.
        Но, тем не менее, разница в скорости между prototype и dojo заставляет задуматься.

  • Tazman

    Неплохая статья. По поводу checkdata_ajax():
    можно сделать двойную функцию типа checkdata_ajax($transport) и в яве что-то типа
    var url = 'путь_к_скрипту' + '/ajax', а в поле action ввести тот же путь, только без аякс. В CI уже обработать переменную и т.д.

    Зы. Вот только почему-то у меня этим способом:
    $res['usernic_error'] = $this->validation->usernic_error;
    $res['password_error'] = $this->validation->password_error;
    $res['usermail_error'] = $this->validation->usermail_error;

    вместо ошибок выдает undefined

    • >> По поводу checkdata_ajax()

      Тоже вариант, но все равно, посетитель при желании может сформировать любой запрос и обратиться к ajax функции.

      >> выдает undefined

      Убедитесь, что вы подключили библиотеку
      $this->load->library(‘validation’);
      и установили поля
      $fields['usernic'] = "ник";
      $fields['fullname'] = "полное имя";
      $fields['usermail'] = "адрес email";
      $this->validation->set_fields($fields);

  • Tazman

    Неплохая статья. По поводу checkdata_ajax():
    можно сделать двойную функцию типа checkdata_ajax($transport) и в яве что-то типа
    var url = 'путь_к_скрипту' + '/ajax', а в поле action ввести тот же путь, только без аякс. В CI уже обработать переменную и т.д.

    Зы. Вот только почему-то у меня этим способом:
    $res['usernic_error'] = $this->validation->usernic_error;
    $res['password_error'] = $this->validation->password_error;
    $res['usermail_error'] = $this->validation->usermail_error;

    вместо ошибок выдает undefined

    • >> По поводу checkdata_ajax()

      Тоже вариант, но все равно, посетитель при желании может сформировать любой запрос и обратиться к ajax функции.

      >> выдает undefined

      Убедитесь, что вы подключили библиотеку
      $this->load->library(‘validation’);
      и установили поля
      $fields['usernic'] = "ник";
      $fields['fullname'] = "полное имя";
      $fields['usermail'] = "адрес email";
      $this->validation->set_fields($fields);

  • Tazman

    С undefind разобрался — очепятки в тексте 🙂

    Тоже вариант, но все равно, посетитель при желании может сформировать любой запрос и обратиться к ajax функции.

    Посетитель то может, но это ему ни чего не даст, т.к. он увидит что-то типа:{”status”:”ERR”,”nic_err”:”»,”name_err”:”»,”email_err”:”»}
    Впрочем, как и на любом другом сайте, если неправильно задать запрос.
    В таком случае хоть будет работать если у посетителя отключен java в браузере 🙂

    • Как я понял, вы предлагаете обеспечить оба варианта работы с формой (с ajax и без него).
      Подход хороший, только работы в 2 раза больше 🙂

  • Tazman

    С undefind разобрался — очепятки в тексте 🙂

    Тоже вариант, но все равно, посетитель при желании может сформировать любой запрос и обратиться к ajax функции.

    Посетитель то может, но это ему ни чего не даст, т.к. он увидит что-то типа:{”status”:”ERR”,”nic_err”:”»,”name_err”:”»,”email_err”:”»}
    Впрочем, как и на любом другом сайте, если неправильно задать запрос.
    В таком случае хоть будет работать если у посетителя отключен java в браузере 🙂

    • Как я понял, вы предлагаете обеспечить оба варианта работы с формой (с ajax и без него).
      Подход хороший, только работы в 2 раза больше 🙂

  • Tazman

    Подход хороший, только работы в 2 раза больше 🙂

    Именно. Зато работать будет везде. Просто у меня уже все было написано без ajax. А потом наткнулся на эту статью — сделал как тут написано, только через mootools и готово 🙂

  • Tazman

    Подход хороший, только работы в 2 раза больше 🙂

    Именно. Зато работать будет везде. Просто у меня уже все было написано без ajax. А потом наткнулся на эту статью — сделал как тут написано, только через mootools и готово 🙂

  • Отличная статья. В мемориз.

  • Отличная статья. В мемориз.

  • Борис

    Если интересно, для jQuery есть плагин для валидации любых форм

    • Спасибо за ссылку.
      Этот плагин мне напомнил библиотеку для проверки форм в CodeIgniter. Правда, наверное все такие библиотеки работают принципу — устанавливаем правила, вызываем функцию validate().

      Еще не разобрался как прикрутить к нему ajax, но общее впечатление очень хорошее.

    • cnfc

      hello

  • Борис

    Если интересно, для jQuery есть плагин для валидации любых форм

    • Спасибо за ссылку.
      Этот плагин мне напомнил библиотеку для проверки форм в CodeIgniter. Правда, наверное все такие библиотеки работают принципу — устанавливаем правила, вызываем функцию validate().

      Еще не разобрался как прикрутить к нему ajax, но общее впечатление очень хорошее.

    • cnfc

      hello

  • Макс

    Супер!

  • Макс

    Супер!

  • Евгений

    Статья супер.. А кто знает где можно почитать о проверке введенных на лету?

    • «на лету» — в смысле без отправки запроса серверу? или с отправкой запросов по мере заполнения формы?

      В любом случае такие проверки делаются с помощью JavaScript. Читаем введенное значение, проверяем и выводим результаты. А проверка может быть локальная либо с выполнение запроса к серверу.

      Почитать… Наверное, лучше всего какую-нибудь книгу о JavaScript или JS библиотеке (например, jQuery).
      Статей и примеров на эту тему очень много, но в них описаны решения конкретных задач, поэтому не знаю что и посоветовать…
      Можно погуглить «javascript form validation»

  • Евгений

    Статья супер.. А кто знает где можно почитать о проверке введенных на лету?

    • «на лету» — в смысле без отправки запроса серверу? или с отправкой запросов по мере заполнения формы?

      В любом случае такие проверки делаются с помощью JavaScript. Читаем введенное значение, проверяем и выводим результаты. А проверка может быть локальная либо с выполнение запроса к серверу.

      Почитать… Наверное, лучше всего какую-нибудь книгу о JavaScript или JS библиотеке (например, jQuery).
      Статей и примеров на эту тему очень много, но в них описаны решения конкретных задач, поэтому не знаю что и посоветовать…
      Можно погуглить «javascript form validation»

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

    • Борис

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

      Никогда так не делайте! На любом скриптовом языке, можно в пять-десять строчек написать скрипт, который будет отправлять вам POST с любыми данными, при этом USER-AGENT у него будет IE, или FF. Да и ip будет с немецкого открытого прокси.
      Проверять именно данные необходимо всегда!

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

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

    • Борис

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

      Никогда так не делайте! На любом скриптовом языке, можно в пять-десять строчек написать скрипт, который будет отправлять вам POST с любыми данными, при этом USER-AGENT у него будет IE, или FF. Да и ip будет с немецкого открытого прокси.
      Проверять именно данные необходимо всегда!

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

  • Petrik

    Сделайте урок по добавлению комментариев на сайт без перезагрузки страници !

    • Борис

      Да, да! Именно так надо просить:
      1. Используйте повелительное наклонение.
      2. В конце поставьте восклицательный знак.
      3. Не употребляйте слов «пожалуйста».
      Только при соблюдении всех пунктов, у любого мимо проходящего, возникнет желание, сразу сделать, всё что вам надо.

    • @Борис, спасибо! Все-таки приятно осознавать, что есть люди, которые обращают внимание на подобные «мелочи» 😉

      По-поводу урока. Нельзя написать о добавлении комментариев без статей о создании блога (или сайта). А я такой цикл в ближайшее время не планирую.
      Кроме того, код добавления комментариев практически не будет отличаться от кода в этой статье. Просто форма будет содержать другие поля. Так что эту статью вполне можно использовать для решения задачи.

  • Petrik

    Сделайте урок по добавлению комментариев на сайт без перезагрузки страници !

    • Борис

      Да, да! Именно так надо просить:
      1. Используйте повелительное наклонение.
      2. В конце поставьте восклицательный знак.
      3. Не употребляйте слов «пожалуйста».
      Только при соблюдении всех пунктов, у любого мимо проходящего, возникнет желание, сразу сделать, всё что вам надо.

    • @Борис, спасибо! Все-таки приятно осознавать, что есть люди, которые обращают внимание на подобные «мелочи» 😉

      По-поводу урока. Нельзя написать о добавлении комментариев без статей о создании блога (или сайта). А я такой цикл в ближайшее время не планирую.
      Кроме того, код добавления комментариев практически не будет отличаться от кода в этой статье. Просто форма будет содержать другие поля. Так что эту статью вполне можно использовать для решения задачи.

  • Castro

    А нету ли подобного примера для проверки полей c jQuery?

    • Возможно вам подойдет этот плагин.

      • Castro

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

        Собственно jQuery скрипт:
        $(document).ready(function() {
        $('#emailid').change(function() {

        var msg = $('#emailid').val();

        $.post("", {message: msg}, function(data) {
        console.log(data);
        if(data=='OK')
        {
        $('messg').html('Bad');
        }
        else $('messg').html('OK');
        });
        });
        });

        emailid — проверяемое поле.

        Контроллер User
        function checkEmail($email){
        if($_POST && $_POST[$email] != NULL){
        $this->usermodel->checkUserByEmail($email);
        }
        else redirect ('user/item_list');
        }

        Ну и модель
        function checkUserByEmail($email)
        {
        $data = array();
        $this->db->where('email',$email);
        $q = $this->db->get('users');
        if($q->num_rows()>0)
        {
        $data = 'OK';
        } else $data = 'NO';
        return $data;
        }

        Сейчас матерится

        Message: Missing argument 1 for User::checkEmail()
        Filename: controllers/user.php

        A PHP Error was encountered

        Severity: Notice
        Message: Undefined variable: email
        Filename: controllers/user.php

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

        • Castro

          В общем-то разобрался, могу поделится кодом, если кому надо.
          Помогла функция $this->db->last_query(); помогающая показать последний запрос, сформированный через Active Record и FirePHP

        • Переменную из формы вы передаете в массиве $_POST, но при этом вы объявили, что методу checkEmail($email) контроллера должен передаваться один параметр (с именем $email), который вы потом пытаетесь использовать при вызове метода модели.
          Кроме того, вы пытаетесь найти в массиве $_POST элемент, используя в качестве ключа переменную $email, которая не определена.

          В общем, я бы изменил код таким образом
          function checkEmail(){
          if($_POST && $_POST['email'] != NULL){
          //или здесь или в модели добавить проверку
          $email = $_POST['email'];
          $this->usermodel->checkUserByEmail($email);
          }
          else redirect ('user/item_list');
          }

          А с точки зрения использования библиотек CI правильнее так
          function checkEmail(){
          if (FALSE !== ($email = $this->input->post('email'))){
          //или здесь или в модели добавить проверку
          $this->usermodel->checkUserByEmail($email);
          }
          else redirect ('user/item_list');
          }

          P.S. Для вашего кода переменная $email будет определена если вы выполните запрос вида
          sitename.domen/user/checkemail/123
          в этом случае
          $email == '123'

  • Castro

    А нету ли подобного примера для проверки полей c jQuery?

    • Возможно вам подойдет этот плагин.

      • Castro

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

        Собственно jQuery скрипт:
        $(document).ready(function() {
        $('#emailid').change(function() {

        var msg = $('#emailid').val();

        $.post("", {message: msg}, function(data) {
        console.log(data);
        if(data=='OK')
        {
        $('messg').html('Bad');
        }
        else $('messg').html('OK');
        });
        });
        });

        emailid — проверяемое поле.

        Контроллер User
        function checkEmail($email){
        if($_POST && $_POST[$email] != NULL){
        $this->usermodel->checkUserByEmail($email);
        }
        else redirect ('user/item_list');
        }

        Ну и модель
        function checkUserByEmail($email)
        {
        $data = array();
        $this->db->where('email',$email);
        $q = $this->db->get('users');
        if($q->num_rows()>0)
        {
        $data = 'OK';
        } else $data = 'NO';
        return $data;
        }

        Сейчас матерится

        Message: Missing argument 1 for User::checkEmail()
        Filename: controllers/user.php

        A PHP Error was encountered

        Severity: Notice
        Message: Undefined variable: email
        Filename: controllers/user.php

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

        • Castro

          В общем-то разобрался, могу поделится кодом, если кому надо.
          Помогла функция $this->db->last_query(); помогающая показать последний запрос, сформированный через Active Record и FirePHP

        • Переменную из формы вы передаете в массиве $_POST, но при этом вы объявили, что методу checkEmail($email) контроллера должен передаваться один параметр (с именем $email), который вы потом пытаетесь использовать при вызове метода модели.
          Кроме того, вы пытаетесь найти в массиве $_POST элемент, используя в качестве ключа переменную $email, которая не определена.

          В общем, я бы изменил код таким образом

          function checkEmail(){
              if($_POST && $_POST['email'] != NULL){
                  //или здесь или в модели добавить проверку
                  $email = $_POST['email'];
                  $this->usermodel->checkUserByEmail($email);
              }
              else redirect ('user/item_list');
          }

          А с точки зрения использования библиотек CI правильнее так

          function checkEmail(){
              if (FALSE !== ($email = $this->input->post('email'))){
                  //или здесь или в модели добавить проверку
                  $this->usermodel->checkUserByEmail($email);
              }
              else redirect ('user/item_list');
          }

          P.S. Для вашего кода переменная $email будет определена если вы выполните запрос вида
          sitename.domen/user/checkemail/123
          в этом случае
          $email == '123'

  • Castro

    P.S. Для вашего кода переменная $email будет определена если вы выполните запрос вида
    sitename.domen/user/checkemail/123
    в этом случае
    $email == '123'

    Вообще, это интересный способ, вот так формировать параметр, в стиле CI. Но, безопасно ли это?
    Кстати, нарыл свежий туториал «Создание Пользовательской корзины с помощью CI и jQuery»

    • А что значит безопасно? Передача данных get или post запросом не менее опасна. Все данные передаются открыто и если кто-то сможет получить доступ к сетевому трафику, то и к этим параметрам он получит доступ тоже.
      Защита существует и называется SSL.

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

      • Castro

        Просто я заменил в одном скринкасте одну забавну штуку

        define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');

        Она не позволяет обратится напрямую к станице, возвращающей значение для скрипта через ajax.

        http://www.weblee.co.uk/2009/06/08/simple-jquery-ajax-with-codeigniter-part-2/
        Где-то в конце ролика показывается как это работает. Помоему неплохо

        • Дело в том, что вы все равно можете обратиться к странице, например, с помощью cURL. И при этом установить все нужные заголовки страницы.
          Этот код удобный, т.к. позволяет отличить обычный запрос от ajax-запроса, но при этом нужно помнить, что проверять все полученные данные все-равно нужно. Т.е. это не способ защиты.

  • Castro

    P.S. Для вашего кода переменная $email будет определена если вы выполните запрос вида
    sitename.domen/user/checkemail/123
    в этом случае
    $email == '123'

    Вообще, это интересный способ, вот так формировать параметр, в стиле CI. Но, безопасно ли это?
    Кстати, нарыл свежий туториал «Создание Пользовательской корзины с помощью CI и jQuery»

    • А что значит безопасно? Передача данных get или post запросом не менее опасна. Все данные передаются открыто и если кто-то сможет получить доступ к сетевому трафику, то и к этим параметрам он получит доступ тоже.
      Защита существует и называется SSL.

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

      • Castro

        Просто я заменил в одном скринкасте одну забавну штуку

        define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');

        Она не позволяет обратится напрямую к станице, возвращающей значение для скрипта через ajax.

        http://www.weblee.co.uk/2009/06/08/simple-jquery-ajax-with-codeigniter-part-2/
        Где-то в конце ролика показывается как это работает. Помоему неплохо

        • Дело в том, что вы все равно можете обратиться к странице, например, с помощью cURL. И при этом установить все нужные заголовки страницы.
          Этот код удобный, т.к. позволяет отличить обычный запрос от ajax-запроса, но при этом нужно помнить, что проверять все полученные данные все-равно нужно. Т.е. это не способ защиты.

  • Алексей

    //сохраняем введенные данные (например, в БД)
    А как именно получить доступ к этим самым данным (имеется ввиду к уже прошедшим проверку из которых уже был удален вредоносный код путем xss_clean). Перечитал руководство — везде пишется одно и тоже — как обработать и отобразить ошибки, а что делать конкретно с данными — нет

    • $usernic = $this->input->post('usernic');
      и т.д.
      Т.е. просто читаете их из массива $_POST, идея в том, что это чтение будет выполняться только если не возникнет ошибок при проверке данных.

      • Алексей

        Спасибо, опытным путем понял, что все действия перечисленные в правилах выполняются над $_POST массивом, и все изменения сохоаняются. Таким образом получается, что
        $rules['usermail'] = "required|valid_email|xss_clean"; эквивалентно $this->input->post('usernic', TRUE); с той лишь разничей, что в первом случае очистка xss будет выполняться вместе с проверкой правил, а во втором — уже после нее.
        Так же выяснил, что $rules['usermail'] = "required|valid_email|xss_clean|callback__user_check все действия функции user_check (если таковые производятся,скажем, удаление ссылок или рисунков, а не просто проверяется на валидность) тоже сохранятся в $_POST массиве.

        • Небольшое уточнение. Менять данные в методе _user_check не совсем правильно. Этот метод должен возвращать true или false в зависимости от результатов проверки.
          Если нужно изменить данные, то лучше прочитать их (сохранить в переменной) и дальше работать с ней.

  • Алексей

    //сохраняем введенные данные (например, в БД)
    А как именно получить доступ к этим самым данным (имеется ввиду к уже прошедшим проверку из которых уже был удален вредоносный код путем xss_clean). Перечитал руководство — везде пишется одно и тоже — как обработать и отобразить ошибки, а что делать конкретно с данными — нет

    • $usernic = $this->input->post('usernic');
      и т.д.
      Т.е. просто читаете их из массива $_POST, идея в том, что это чтение будет выполняться только если не возникнет ошибок при проверке данных.

      • Алексей

        Спасибо, опытным путем понял, что все действия перечисленные в правилах выполняются над $_POST массивом, и все изменения сохоаняются. Таким образом получается, что
        $rules['usermail'] = "required|valid_email|xss_clean"; эквивалентно $this->input->post('usernic', TRUE); с той лишь разничей, что в первом случае очистка xss будет выполняться вместе с проверкой правил, а во втором — уже после нее.
        Так же выяснил, что $rules['usermail'] = "required|valid_email|xss_clean|callback__user_check все действия функции user_check (если таковые производятся,скажем, удаление ссылок или рисунков, а не просто проверяется на валидность) тоже сохранятся в $_POST массиве.

        • Небольшое уточнение. Менять данные в методе _user_check не совсем правильно. Этот метод должен возвращать true или false в зависимости от результатов проверки.
          Если нужно изменить данные, то лучше прочитать их (сохранить в переменной) и дальше работать с ней.

  • Алексей

    Итого имеем, к примеру
    $rules['usernic'] = "required|min_length[3]|max_length[10]";
    Если все норм if ($this->validation->run() == TRUE) {
    $usernic = $this->input->post('usernic', TRUE); //очистили от xss
    $usernic = user_check($usernic); //выполнили свои дйствия
    }

    Просто в документации по CI встретил такие приммеры
    $rules['usernic'] = "required|xss_clean";
    А ведь xss_clean не возвращает TRUE or FALSE, поэтому и вышла такая непонятка))

    • Теперь я понял в чем вопрос заключается 🙂
      Дело в том, что в перечне правил вы можете использовать практически все фунции php, которые принимают один аргумент. Например, md5, trim и т.п.
      Т.е. строка
      $usernic = $this->input->post('usernic', TRUE);
      совсем не обязательна, если в правилах вы указываете
      «…|xss_clean»
      Но если нужно использовать функцию сторонней библиотеки, то лучше это сделать после проверки введенных данных.
      Например,


      $rules['usernic'] = «required|xss_clean»;

      if ($this->validation->run() == TRUE) {
      //загружаем библиотеку
      //получаем данный из post ($usernic = $this->input->post('usernic'))
      //используем методы библиотеки
      }

  • Алексей

    Итого имеем, к примеру
    $rules['usernic'] = "required|min_length[3]|max_length[10]";
    Если все норм if ($this->validation->run() == TRUE) {
    $usernic = $this->input->post('usernic', TRUE); //очистили от xss
    $usernic = user_check($usernic); //выполнили свои дйствия
    }

    Просто в документации по CI встретил такие приммеры
    $rules['usernic'] = "required|xss_clean";
    А ведь xss_clean не возвращает TRUE or FALSE, поэтому и вышла такая непонятка))

    • Теперь я понял в чем вопрос заключается 🙂
      Дело в том, что в перечне правил вы можете использовать практически все фунции php, которые принимают один аргумент. Например, md5, trim и т.п.
      Т.е. строка
      $usernic = $this->input->post('usernic', TRUE);
      совсем не обязательна, если в правилах вы указываете
      «…|xss_clean»
      Но если нужно использовать функцию сторонней библиотеки, то лучше это сделать после проверки введенных данных.
      Например,

      ...
      $rules['usernic'] = "required|xss_clean";
      ...
      if ($this->validation->run() == TRUE) {
          //загружаем библиотеку
          //получаем данный из post ($usernic = $this->input->post('usernic')) 
          //используем методы библиотеки
      }
  • А как быть если форма содержит массив checkbox-ов?!
    Ну я имею ввиду, если форма содержит такие строки:

    Как тогда будет выглядеть функция sendData(), а именно строка с параметрами запроса?

    И еще один вопрос! Возможно ли сдалать такую ajax-форму, которая бы отправляла письма с вложениями???

    Заранее спасибо!

    • А как быть если форма содержит массив checkbox-ов?!

      Тут все зависит от вашего воображения 😉
      Наверное, самый удобный вариант — сформировать запрос также как и при обычной отправке.
      Т.е. если есть массив с чекбоксами
      … type=»checkbox» name=»my_chekbox[]»…
      то строку запроса формируем с помощью цикла:
      1) проходим по всем чекбоксам формы
      2) если чекбокс отмечен, добавляем его в строку запроса

      Например, если отмечено два чекбокса, то в запросе нужно передать
      my_chekbox[]:значение_1
      my_chekbox[]:значение_2

      Этот вариант лучше, т.к. не нужно будет писать два варианта кода серверной (php) части для разбора полученных данных. Т.е. проще сделать форму, которая будет работать с использованием ajax и без него.

      Но, как я написал в начале, вас ничто не ограничивает. Например, можно сформировать массив с данными формы, преобразовать его в json формат и отправить в одном параметре.

      Что касается отправки файлов. У меня есть статья на эту тему 😉 Как реализовать асинхронную загрузку файлов с помощью JavaScript и PHP

  • А как быть если форма содержит массив checkbox-ов?!
    Ну я имею ввиду, если форма содержит такие строки:

    Как тогда будет выглядеть функция sendData(), а именно строка с параметрами запроса?

    И еще один вопрос! Возможно ли сдалать такую ajax-форму, которая бы отправляла письма с вложениями???

    Заранее спасибо!

    • А как быть если форма содержит массив checkbox-ов?!

      Тут все зависит от вашего воображения 😉
      Наверное, самый удобный вариант — сформировать запрос также как и при обычной отправке.
      Т.е. если есть массив с чекбоксами
      … type=»checkbox» name=»my_chekbox[]»…
      то строку запроса формируем с помощью цикла:
      1) проходим по всем чекбоксам формы
      2) если чекбокс отмечен, добавляем его в строку запроса

      Например, если отмечено два чекбокса, то в запросе нужно передать
      my_chekbox[]:значение_1
      my_chekbox[]:значение_2

      Этот вариант лучше, т.к. не нужно будет писать два варианта кода серверной (php) части для разбора полученных данных. Т.е. проще сделать форму, которая будет работать с использованием ajax и без него.

      Но, как я написал в начале, вас ничто не ограничивает. Например, можно сформировать массив с данными формы, преобразовать его в json формат и отправить в одном параметре.

      Что касается отправки файлов. У меня есть статья на эту тему 😉 Как реализовать асинхронную загрузку файлов с помощью JavaScript и PHP

  • А как получить значение выбранного чекбокса из массива?

    Так :
    var chek = $('my_chekbox[0]').value;

    • Я бы сделал немного по-другому.

      <form action="#" method="post" id="my_form">
      <p>
      <label><input type="checkbox" name="my_checkbox[]" value="1" />1</label>
      <label><input type="checkbox" name="my_checkbox[]" value="2" />2</label>
      <label><input type="checkbox" name="my_checkbox[]" value="3" />3</label>
      <input type="submit" value="Отправить" />
      </p>
      </form>

      $(function() {
      $('#my_form').submit(function() {
      var mc = $('input:checked');
      mc.each(function() {
      alert($(this).val());
      });
      return false;
      });
      });

  • А как получить значение выбранного чекбокса из массива?

    Так :
    var chek = $('my_chekbox[0]').value;

    • Я бы сделал немного по-другому.

      <form action="#" method="post" id="my_form">
      	<p>
      		<label><input type="checkbox" name="my_checkbox[]" value="1" />1</label>
      		<label><input type="checkbox" name="my_checkbox[]" value="2" />2</label>
      		<label><input type="checkbox" name="my_checkbox[]" value="3" />3</label>
      		<input type="submit" value="Отправить" />
      	</p>
      </form>
      
      $(function() {
          $('#my_form').submit(function() {
              var mc = $('input:checked');
              mc.each(function() {
                  alert($(this).val());
              });
              return false;
          });
      });
  • Спасибо Владимир!
    Я в jquery не очень силен, поэтому хотел Вас попросить показать как это прикрутить к скрипту scripts.js, который Вы рассматриваете в начале этой статьи!

    • Извините, я забыл, что в этом примере использовал prototype, а не jQuery. Последнее время я практически полностью перешел на jQuery, т.к. она удобнее и не такая тяжелая.

      Строку 6 первого листинга нужно изменить так
      <script type=»text/javascript» src=»<?php echo base_url(); ?>jquery-1.3.2.min.js»></script>
      (естественно, предварительно нужно скачать библиотеку)

      Код, который я привел в предыдущем комментарии должен находиться в файле scripts.js.
      Остальной код в этом файле нужно немного переписать.
      Вместо Ajax.Request использовать $.post(…). Пример использования есть на оф. сайте jQuery.

  • Спасибо Владимир!
    Я в jquery не очень силен, поэтому хотел Вас попросить показать как это прикрутить к скрипту scripts.js, который Вы рассматриваете в начале этой статьи!

    • Извините, я забыл, что в этом примере использовал prototype, а не jQuery. Последнее время я практически полностью перешел на jQuery, т.к. она удобнее и не такая тяжелая.

      Строку 6 первого листинга нужно изменить так
      <script type=»text/javascript» src=»<?php echo base_url(); ?>jquery-1.3.2.min.js»></script>
      (естественно, предварительно нужно скачать библиотеку)

      Код, который я привел в предыдущем комментарии должен находиться в файле scripts.js.
      Остальной код в этом файле нужно немного переписать.
      Вместо Ajax.Request использовать $.post(…). Пример использования есть на оф. сайте jQuery.

  • Dreamer

    Помогите пожалуйста передать значение в функцию PHP.

    Файл func.js
    function probajs() {
    var p = $('text').value;
    var pars = $H({par:p}).toQueryString();
    new Ajax.Request(«http://ci_sample/proba/proba_ajax»,
    {method:»post», parameters:pars, onSuccess:parseResponse});
    }
    function parseResponse(param) {
    var data = eval('(' + param.responseText + ')');
    $('pajax').innerHTML = data.par;
    }
    Файл в контроллере proba.php
    function proba_ajax() {
    $par = ;// как правильно тут написать?
    $res['par'] = $par*4;
    echo json_encode($res);
    }

    • Dreamer

      Всё разобрался. Может кому пригодиться
      $res['par'] = $this->input->post('par');

  • Dreamer

    Помогите пожалуйста передать значение в функцию PHP.

    Файл func.js
    function probajs() {
    var p = $('text').value;
    var pars = $H({par:p}).toQueryString();
    new Ajax.Request(«http://ci_sample/proba/proba_ajax»,
    {method:»post», parameters:pars, onSuccess:parseResponse});
    }
    function parseResponse(param) {
    var data = eval('(' + param.responseText + ')');
    $('pajax').innerHTML = data.par;
    }
    Файл в контроллере proba.php
    function proba_ajax() {
    $par = ;// как правильно тут написать?
    $res['par'] = $par*4;
    echo json_encode($res);
    }

    • Dreamer

      Всё разобрался. Может кому пригодиться
      $res['par'] = $this->input->post('par');

  • open

    Почему ошибки не передаются ajaxoм, хотя без ajax всё работает

    • Почему не передаются?
      Они добавляются в массив $res — строки 14-17 (третий листинг)

  • Arax

    privet cac dela

  • Максим

    Не могу загрузить вьюшку при выполнении условия проверки данных. Подскажите как можно это сделать? Привожу пример: в вашем коде, где у вас проверены данные они к примеру сохраняются в базу данных. Мне в этом случае нужно сделать загрузку представления. Пишу $this->load->view('faddress');, но ничего не происходит. И еще как сделать, чтоб можно было передавать кириллицу?

    • Если
      $this->load->view('faddress');
      находится внутри условия (оператора if) и файл view существует, то это значит, что условие не выполняется. Проверяйте передаваемые данные.

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

      • Максим

        Спасибо за ответ. Кириллица заработала. Но view так и не грузится. Хотя условие выполняется.
        Ajax запрос передается функции results().public function results() {

        $this->form_validation->set_rules('group1','Условие поиска', 'required');
        if ($this->form_validation->run() == TRUE){
        $this->load->view('faddress');
        //$res['group1'] = «ВСЕ ОК»;
        //echo json_encode($res);
         }
        }Вот к примеру если я оставлю только         $res['group1'] = «ВСЕ ОК»; echo json_encode($res);то на странице это отобразится. Получается условие выполняется. Оставляю $this->load->view('faddress'); ничего не происходит. 

        • У вас точно есть файл faddress.php в папке application/views/?

        • Максим

          Точно есть. Я проверял это обычной загрузкой view(по ссылке на контроллер, который загружает представление) без аякса.

        • Идеи у меня закончились 😉 Поэтому пакуйте папку application вместе с index.php в архив и отправляйте мне почтой (ссылка в сайдбаре). Попробую разобраться в чем дело.

  • Mandarin154

    Подскажите пожалуйста, правильно ли я понял, когда мы описываем функцию SendData, мы передаем параметр  » «. Он содержит  путь где мы находится в данный момент? 
    Спрашиваю, потому что с ним у меня некорректно работает отображение страницы (нету ни кнопки, ни стилей. просто текст)

    • Mandarin154

      Извиняюсь, видимо вставка кода не прошла экранирование. Вообщем в » »  подразумевалось строчка «пхп эхо бэйс юрл»

    • Нет, в SendData нужно передать просто адрес сервера
      (baseURL). Т.е. baseURL + «index.php/main/checkdata_ajax» — должен получится адрес скрипта, который обрабатывает ajax запрос.

  • Arkady Sladkoff

    Это видимо для какого-то старого CI. А что насчет либы form_validation? $res['nic_err'] = $this->form_validation->usernic_error; не работает. Как передать ошибки джейсоном?

    • Да, вы правы. Статья написана в начале 2008.
      Для того, чтобы передать ошибки в JSON формате, их описание нужно добавить в массив и затем вызвать json_encode.

      • Arkady Sladkoff

        это-то понятно 🙂 Не корректно задал вопрос. Как получить ошибки? В стандартной доке предлагается использовать хелпер form_error. Но нет никаких пременных, которые можно добавить в массив, с которым потом вызвать json_encode. Т.е. никак? Или все-таки есть варианты?

        • Вы можете использовать метод error_array() для того, чтобы получить описания ошибок в виде массива.

          $this->form_alidation->error_array()

          В их user guide этот метод, не упоминается, но в исходниках видно, что он есть.

        • Arkady Sladkoff

          спасибо большое

        • Arkady Sladkoff

          Call to undefined method CI_Form_validation::error_array()

        • Arkady Sladkoff

          если вдруг кому станет интересно, то я решил проблему так:

          создал свою либу:
          class Extended_form_validation extends CI_Form_validation {

          public function getErrors(){
          return $this->_error_array;
          }
          }

          в контроллере

          $this->load->library('form_validation');
          $this->load->model('rules_model');
          $this->form_validation->set_rules($this->rules_model->reg_form_rules);
          if($this->form_validation->run() == FALSE){
          $res = $this->form_validation->getErrors();
          echo json_encode($res);
          }

        • Похоже на github версия фреймворка отличается от вашей. Т.к. вы фактически повторили код метода error_array()

  • Bagunda

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

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