codeigniter UTF8対応とモバイルセッション対応


## UTF-8対応
```php
<?php

class MY_Utf8 extends CI_Utf8 {

	function __construct(){
		parent::__construct();
	}

	/**
	 * Clean UTF-8 strings
	 *
	 * Ensures strings are UTF-8
	 *
	 * mobile対応で、SJIS-win => utf-8 に変換するため、サニタイズ前に変換する必要がある
	 * とくにauは、htmlのaccept-charsetでは、utf-8には変換されないため対応が必須
	 *
	 * @access	public
	 * @param	string
	 * @return	string
	 */
	function clean_string($str)
	{
		if ($this->_is_ascii($str) === FALSE)
		{
			if (mb_detect_encoding($str) != 'UTF-8') $str = mb_convert_encoding($str, "UTF-8", "auto");
			$str = @iconv('UTF-8', 'UTF-8//IGNORE', $str);
		}

		return $str;
	}
}

```

## モバイルsession対応

1. テーブルの追加
2. configの変更
4. routes.phpに追記

```php:config.php
$config['sess_cookie_name']		= 'gk_session';
$config['sess_expiration']		= 7200;
$config['sess_expire_on_close']	= FALSE;
$config['sess_encrypt_cookie']	= TRUE;
$config['sess_use_database']	= TRUE;
$config['sess_table_name']		= 'ci_sessions';
$config['sess_match_ip']		= FALSE;
$config['sess_match_useragent']	= TRUE;
$config['sess_time_to_update']	= 300;

$config['permitted_uri_chars'] = '= a-z 0-9~%.:_-';

$config['csrf_protection'] = FALSE;

```

```php:routes.php

$route['(.*)SESSID=.*$']     = "$1";

```


※session_idは、セッションハイジャック対策のため毎回更新される。

```php

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
 * this MY_Session subclass is database assosiation.
 * execute before 'ci_sessions' table createing.
 *
 * CREATE TABLE IF NOT EXISTS `ci_sessions` (
 * 	session_id varchar(40) DEFAULT '0' NOT NULL,
 * 	ip_address varchar(16) DEFAULT '0' NOT NULL,
 * 	user_agent varchar(120) NOT NULL,
 * 	last_activity int(10) unsigned DEFAULT 0 NOT NULL,
 * 	user_data text NOT NULL,
 * 	PRIMARY KEY (session_id),
 * 	KEY `last_activity_idx` (`last_activity`)
 * );
 *
 * this MY_session subclass is configure settiong
 * to permitted_uri_char addition '='.
 *
 * $config['permitted_uri_chars'] = '= a-z 0-9~%.:_-';
 *
 * this MY_session subclass is config routes settiong
 * to 'SESSID' additions.
 *
 * $route['(.*)SESSID=.*$'] = "$1";
 */

/**
 * MY_Session
 *
 * @package    example.com
 * @subpackage CI_Session
 * @author    name <xxxxxxxxxxx@gmail.com>
 */
class MY_Session extends CI_Session {

	var $couldnt_read_cookie = FALSE;

	/**
	 * __construct
	 *
	 * @access public
	 * @return void
	 */
	function __construct()
	{
		parent::__construct();
	}

	// --------------------------------------------------

	/**
	 * Fetch the current session data if it exists
	 *
	 * @access	public
	 * @return	bool
	 */
	function sess_read()
	{
		// Fetch the cookie
		$session = $this->CI->input->cookie($this->sess_cookie_name);

		// No cookie?  Goodbye cruel world!...
		if ($session === FALSE)
		{
			//Remember that I couldn't read the cookie
			$this->couldnt_read_cookie = TRUE;

			//Attempt to load sess_id from url
			$url_session = array();
			preg_match ( "|SESSID=[^/\\\\]*|", $this->CI->uri->segment($this->CI->uri->total_segments()), $url_session);

			if (empty ($url_session))
			{
				log_message('debug', 'A session cookie was not found.');
				return FALSE;
			}
			else
			{
				$this->CI->db->where('session_id', str_replace("SESSID=", "", $url_session[0]));
				$query = $this->CI->db->get($this->sess_table_name);

				// No result?  Kill it!
				if ($query->num_rows() == 0)
				{
					$this->sess_destroy();
					return FALSE;
				}
				foreach ($query->result_array() as $row)
				{
					$session['session_id']    = $row['session_id'];
					$session['last_activity'] = $row['last_activity'];
					$session['user_agent']    = $row['user_agent'];
					$session['ip_address']    = $row['ip_address'];
				}
			}
		}
		else
		{
			// 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, 120)))
		{
			$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;
	}

	// --------------------------------------------------

	/**
	* sess_write
	*
	* @access    public
	* @return    void
	*/
	function sess_write()
	{
		parent::sess_write();

		//If I couldn't read the cookie last time, attach session data to
		//url in case I can't read the cookie in future attempts
		//This functionality demands that URLs are created using CI
		//tools such as URL helper or reminding to always attach the url
		//suffix (even if you don't define one
		if ( $this->couldnt_read_cookie )
		{
			//Unset in case we rewrite the session
			$this->couldn_read_cookie = FALSE;

			$sessid = $this->userdata['session_id'];
			$this->CI->config->set_item ('url_suffix','/SESSID='. $sessid. config_item ('url_suffix'));
		}

		//Save userdata in database
		if ($this->sess_use_database === TRUE)
		{
			$custom_userdata = $this->userdata;

			foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
			{
				unset($custom_userdata[$val]);
			}

			$set = array (
						"session_id" => $this->userdata['session_id'],
						"ip_address" => $this->userdata['ip_address'],
						"user_agent" => $this->userdata['user_agent'],
						"last_activity" => $this->userdata['last_activity'],
						"user_data" => serialize ( $custom_userdata )
						);
			$this->CI->db->where ( "session_id", $this->userdata ( 'session_id' ) );
			$this->CI->db->update ( $this->sess_table_name, $set );
		}
	}
}

/* End of file MY_Session.php */
/* Location: ./application/libraries/MY_Session.php */
```