I am running a Codeigniter 2.0 web app, and I am using the sessions library with the DB option on, so for every connection on my website I have a MySQL table called 'ci_sessions'
that stores:
Session_id
- IP address
- User_agent
- Last_activity
- User_data
And I have two issues:
- Google bot with IP
66.249.72.152
- Cron with IP
0.0.0.0
Everytime my server runs the cron or every time the google bot crawls my page a new session is created. So I have hundreds of identical sessions with the IP 0.0.0.0
and hundreds with the IP 66.249.72.152
.
Does anyone know how to stop the bot or the cron from creating sessions? Or if this can not be done... does anyone know how to automatically delete these sessions every once in a while? Thanks!
A possible solution could be to implement a blacklist of IP's that a session should not be created for.
I have created two methods of doing this:
application/config/config.php
/*
|--------------------------------------------------------------------------
| Session Variables
|--------------------------------------------------------------------------
|
| 'sess_cookie_name' = the name you want for the cookie
| 'sess_expiration' = the number of SECONDS you want the session to last.
| by default sessions last 7200 seconds (two hours). Set to zero for no expiration.
| 'sess_expire_on_close' = Whether to cause the session to expire automatically
| when the browser window is closed
| 'sess_encrypt_cookie' = Whether to encrypt the cookie
| 'sess_use_database' = Whether to save the session data to a database
| 'sess_table_name' = The name of the session database table
| 'sess_match_ip' = Whether to match the user's IP address when reading the session data
| 'sess_match_useragent' = Whether to match the User Agent when reading the session data
| 'sess_time_to_update' = how many seconds between CI refreshing Session Information
| 'sess_ignore_ip' = array of IP addresses to ignore
|
*/
$config['sess_cookie_name'] = 'ci_session';
$config['sess_expiration'] = 7200;
$config['sess_expire_on_close'] = FALSE;
$config['sess_encrypt_cookie'] = FALSE;
$config['sess_use_database'] = FALSE;
$config['sess_table_name'] = 'ci_sessions';
$config['sess_match_ip'] = FALSE;
$config['sess_match_useragent'] = TRUE;
$config['sess_time_to_update'] = 300;
$config['sess_ignore_ip'] = array('66.249.72.152', '0.0.0.0');
system/libraries/session.php
/**
* Session Constructor
*
* The constructor runs the session routines automatically
* whenever the class is instantiated.
*/
public function __construct($params = array())
{
log_message('debug', "Session Class Initialized");
// Set the super object to a local variable for use throughout the class
$this->CI =& get_instance();
// Set all the session preferences, which can either be set
// manually via the $params array above or via the config file
foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key', 'sess_ignore_ip') as $key)
{
$this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);
}
if ($this->encryption_key == '')
{
show_error('In order to use the Session class you are required to set an encryption key in your config file.');
}
// Load the string helper so we can use the strip_slashes() function
$this->CI->load->helper('string');
// Do we need encryption? If so, load the encryption class
if ($this->sess_encrypt_cookie == TRUE)
{
$this->CI->load->library('encrypt');
}
// Are we using a database? If so, load it
if ($this->sess_use_database === TRUE AND $this->sess_table_name != '')
{
$this->CI->load->database();
}
// Set the "now" time. Can either be GMT or server time, based on the
// config prefs. We use this to set the "last activity" time
$this->now = $this->_get_time();
// Set the session length. If the session expiration is
// set to zero we'll set the expiration two years from now.
if ($this->sess_expiration == 0)
{
$this->sess_expiration = (60*60*24*365*2);
}
// Set the cookie name
$this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
$ip_address = $this->CI->input->ip_address();
if(!isset($this->sess_ignore_ip) || empty($this->sess_ignore_ip) || !in_array($ip_address, $this->sess_ignore_ip))
{
// Run the Session routine. If a session doesn't exist we'll
// create a new one. If it does, we'll update it.
if ( ! $this->sess_read())
{
$this->sess_create();
}
else
{
$this->sess_update();
}
}
// Delete 'old' flashdata (from last request)
$this->_flashdata_sweep();
// Mark all new flashdata as old (data will be deleted before next request)
$this->_flashdata_mark();
// Delete expired sessions if necessary
$this->_sess_gc();
log_message('debug', "Session routines successfully run");
}
/**
* Garbage collection
*
* This deletes expired session rows from database
* if the probability percentage is met
*
* @access public
* @return void
*/
function _sess_gc()
{
if ($this->sess_use_database != TRUE)
{
return;
}
srand(time());
if ((rand() % 100) < $this->gc_probability)
{
$expire = $this->now - $this->sess_expiration;
$this->CI->db->where("last_activity < {$expire}");
if(isset($this->sess_ignore_ip) && !empty($this->sess_ignore_ip))
$this->db->where_in('ip_address', $this->sess_ignore_ip);
$this->CI->db->delete($this->sess_table_name);
log_message('debug', 'Session garbage collection performed.');
}
}
The config file contains an array of IP addresses to ignore.
In the session library, I have updated the constructor, so that it checks to see if the current IP address exists in the above config setting and if so, skips the code that creates or updates the session.
In addition to this, in _sess_gc
I have added new where_in statement that will delete all session rows that have an IP that matches those in the config. If you implement the constructor method, you don't really need this part.
I suggest not to modify core files, I recommend to extend the session class, so do the next thing create MY_Session.php file in ./app/libraries/ and paste the next code
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* ------------------------------------------------------------------------
* CI Session Class Extension
* ------------------------------------------------------------------------
*
*/
class MY_Session extends CI_Session {
/**
* sess_update()
*
* Do not create session if it's in the cli environment
*
* @access public
* @return void
*/
public function sess_create()
{
$CI = get_instance();
$ip_address = $CI->input->ip_address();
if ( ($ip_address != '0.0.0.0' && $CI->input->user_agent() != '0') || $ip_address != '66.249.72.152'){
parent::sess_create();
}
}
}
/* End of file MY_Session.php */
/* Location: ./app/libraries/MY_Session.php */
?>
this works
In case you want to look at this using the user agent
I created a library drop in, to block bots by their user-agent, using a simple $this->agent->is_robot()
check for drop in session extension.
https://github.com/donjakobo/codeigniter-clean-sessions
Alter your ci_sessions table and add the UNIQUE constraint to ip_address field. That way there will be no duplicate sessions..
A more complicated approach would be to use a trigger on insert. That will check whether the ip address is among the two addresses that you mentioned above. If yes, then donot insert in the db..