К сожалению, тестирование кода показало, что сессия кодеигнитера не самое лучшее место для хранения секретного кода.
Давайте отключим автоматическую загрузку сессий
в файле /application/config/autoload.php строку
$autoload['libraries'] = array('database', 'session',);
заменяем обратно на
$autoload['libraries'] = array('database',);
Все остальные настройки кук мы оставим как и прежде, они нам еще пригодятся.
Апи каптчи
Нам нужно какое-то апи для хранения и получения данных каптчи. Для начала будем хранить их в БД. Потом, если захотим, перепишем хранение на Мемкешед или редис.
Создаем файл /application/models/captcha_api.php
<?php
/**
* Работаем с капчей
*/
class Captcha_api extends CI_Model {
/**
* Время в секундах, пока каптча принимается
*/
var $timeout = 1800;
/**
* сохранить новую каптчу
*/
function save($captcha, $user_agent = null) {
if (!$user_agent) {
$user_agent = $this->user_agent();
}
$this->db->set('captcha', trim(strtolower($captcha)));
$this->db->set('user_agent', substr($user_agent, 0, 50));
$this->db->set('created', time());
$this->db->insert('captcha');
if (mt_rand(0, 100) < 5) {
$this->clean_old();
}
}
/**
* проверим каптчу
*/
function check($captcha, $user_agent = null) {
if (!$user_agent) {
$user_agent = $this->user_agent();
}
$this->db->where('captcha', trim(strtolower($captcha)));
$this->db->where('user_agent', substr($user_agent, 0, 50));
$this->db->where('created >', time() - $this->timeout);
$query = $this->db->get('captcha');
return $query->num_rows() > 0;
}
/**
* удалить использованную каптчу
*/
function delete($captcha, $user_agent = null) {
if (!$user_agent) {
$user_agent = $this->user_agent();
}
$this->db->where('captcha', trim(strtolower($captcha)));
$this->db->where('user_agent', substr($user_agent, 0, 50));
$this->db->delete('captcha');
}
/**
* удалим старую
*/
function clean_old() {
$this->db->where('created <', time() - $this->timeout);
$this->db->delete('captcha');
}
function user_agent() {
return $_SERVER['HTTP_USER_AGENT'];
}
}
Метод save сохраняет новую секретную строку в базу. Мы используем HTTP_USER_AGENT для дополнительной проверки того, кто запрашивает каптчу. Если бы были везде включены сессии (плохая практика), то можно было бы использовать ид сессии и так было бы надежнее.
Метод check проверяет наличие секретной строки.
Метод delete удаляет указанную секретную строку, например когда она использована. Если не удалять каптчу, то еще какое-то довольно продолжительное время эту каптчу можно будет повторно использовать в куче мест.
Поскольку мы храним данные в БД, то надо очищать ее от устаревших данных. Для этого служит метод clean_old, который мы иногда вызываем при записи новой секретной строки.
Таблица в которой мы храним данные вот такая
CREATE TABLE IF NOT EXISTS `captcha` ( `captcha` varchar(10) NOT NULL, `user_agent` varchar(50) NOT NULL, `created` int(11) NOT NULL, KEY `captcha` (`captcha`), KEY `created` (`created`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
