Подмена сессии для Flash-загрузчиков
Материал из Wiki
Исторически сложилось, что Flash-загрузчики, не передают куки во время обращения к серверу(исключение: передаются только через IE). Чтобы передавать данные сессии, проще всего вставлять данные сессии в скрипт Flash-загрузчика, а после передавать через GET или POST. Для данного решения, лучше использовать POST из-за тонкости в реализации. Естественно решение подходит и для DX Auth, и для других библиотек авторизации, которые используют родные сессии CodeIgniter'а.
Способ 1(плохой): изменение core-библиотеки
В библиотеке Session.php, в функции sess_read() нужно поменять самое начало кода:
function sess_read()
{
// Fetch the cookie
$session = $this->CI->input->cookie($this->sess_cookie_name);
/*Добавляем этот код.
Здесь для уверенности в том, что это Flash-загрузчик проверяем user agent. Учтите, что для разных загрузчиков user agent может быть разным.
*/
$this->object =& get_instance();
if ( stristr($this->object->input->user_agent(),'Shockwave Flash') || stristr($this->object->input->user_agent(),'Adobe Flash Player') )
{
//Записываем данные сессии, полученные из POST.
$session = $this->CI->input->post($this->sess_cookie_name);
}
//...............
}
Способ 2(приемлемый): расширение core-библиотеки
Чтобы ничего не изменять в системных файлах фреймворка, лучше использовать расширение его классов своими. Для этого, нижеприведенный код сохраните в /application/libraries/MY_Session.php
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class MY_Session extends CI_Session{
protected
$new_ua = ''
;
function __construct() {
if(version_compare(CI_VERSION,'1.7.3') > 0)
{
parent::__construct();
} else {
parent::CI_Session();
}
}
function MY_Session()
{
$this->__construct();
}
function sess_read()
{
// Fetch the cookie
$session = $this->CI->input->cookie($this->sess_cookie_name);
if ( stristr($this->CI->input->user_agent(),'Shockwave Flash') || stristr($this->CI->input->user_agent(),'Adobe Flash Player') )
{
log_message('debug', 'Flash uploader');
$session = $this->CI->input->post($this->sess_cookie_name);
$this->new_ua = $this->CI->input->user_agent();
/*Отмена проверки user_agent*/
$this->sess_match_useragent = FALSE;
/*Замена пробелов на плюсы*/
if ($this->sess_encrypt_cookie == TRUE)
{
$session = str_replace(' ','+',$session);
}
}
// No cookie? Goodbye cruel world!...
if ($session === FALSE)
{
log_message('debug', 'A session cookie was not found.');
return FALSE;
}
// Decrypt the cookie data
if ($this->sess_encrypt_cookie == TRUE)
{
$session = $this->CI->encrypt->decode($session);
}
else
{
// encryption was not used, so we need to check the md5 hash
$hash = substr($session, strlen($session)-32); // get last 32 chars
$session = substr($session, 0, strlen($session)-32);
// Does the md5 hash match? This is to prevent manipulation of session data in userspace
if ($hash !== md5($session.$this->encryption_key))
{
log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.');
$this->sess_destroy();
return FALSE;
}
}
// Unserialize the session array
$session = $this->_unserialize($session);
// Is the session data we unserialized an array with the correct format?
if ( ! is_array($session) OR ! isset($session['session_id']) OR ! isset($session['ip_address']) OR ! isset($session['user_agent']) OR ! isset($session['last_activity']))
{
$this->sess_destroy();
return FALSE;
}
// Is the session current?
if (($session['last_activity'] + $this->sess_expiration) < $this->now)
{
$this->sess_destroy();
return FALSE;
}
// Does the IP Match?
if ($this->sess_match_ip == TRUE AND $session['ip_address'] != $this->CI->input->ip_address())
{
$this->sess_destroy();
return FALSE;
}
// Does the User Agent Match?
if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 50)) AND empty($this->new_ua) )
{
$this->sess_destroy();
return FALSE;
}
// Is there a corresponding session in the DB?
if ($this->sess_use_database === TRUE)
{
$this->CI->db->where('session_id', $session['session_id']);
if ($this->sess_match_ip == TRUE)
{
$this->CI->db->where('ip_address', $session['ip_address']);
}
if ($this->sess_match_useragent == TRUE)
{
$this->CI->db->where('user_agent', $session['user_agent']);
}
$query = $this->CI->db->get($this->sess_table_name);
// No result? Kill it!
if ($query->num_rows() == 0)
{
$this->sess_destroy();
return FALSE;
}
// Is there custom data? If so, add it to the main session array
$row = $query->row();
if (isset($row->user_data) AND $row->user_data != '')
{
$custom_data = $this->_unserialize($row->user_data);
if (is_array($custom_data))
{
foreach ($custom_data as $key => $val)
{
$session[$key] = $val;
}
}
}
}
// Session is valid!
$this->userdata = $session;
unset($session);
return TRUE;
}
}
?>
И все, теперь при использовании Flash-загрузчиков можно не волноваться за сессии.
View
Вот фрагмент скрипта для Flash-загрузчика Uploadify:
<script type="text/javascript">
$(document).ready(function() {
$("#userfile").uploadify({
'uploader' : '<?=$this->config->item('base_url'); ?>/js/uploadify.swf',
'script' : '<?=$this->config->item('base_url'); ?>/index.php/photo/upload',
'fileDataName' : 'userfile',
//Обратите внимание на то, что метод указан POST
'method': 'POST',
//Передаваемые скриптом данные - это имя куки и ее содержимое.
'scriptData' : {'<?=$sess_cookie_name; ?>' : '<?=$sess_cookie; ?>'}
});
});
</script>