Подмена сессии для 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>
Личные инструменты