/lenasys/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/lenasys/trunk
20.1.1 by galaxyAbstractor
* Added an simple admin panel to the codeviewer-cmssy stuff
1
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2
/**
3
 * CodeIgniter
4
 *
5
 * An open source application development framework for PHP 5.1.6 or newer
6
 *
7
 * @package		CodeIgniter
8
 * @author		ExpressionEngine Dev Team
9
 * @copyright	Copyright (c) 2008 - 2011, EllisLab, Inc.
10
 * @license		http://codeigniter.com/user_guide/license.html
11
 * @link		http://codeigniter.com
12
 * @since		Version 1.0
13
 * @filesource
14
 */
15
16
// ------------------------------------------------------------------------
17
18
/**
19
 * Session Class
20
 *
21
 * @package		CodeIgniter
22
 * @subpackage	Libraries
23
 * @category	Sessions
24
 * @author		ExpressionEngine Dev Team
25
 * @link		http://codeigniter.com/user_guide/libraries/sessions.html
26
 */
27
class CI_Session {
28
29
	var $sess_encrypt_cookie		= FALSE;
30
	var $sess_use_database			= FALSE;
31
	var $sess_table_name			= '';
32
	var $sess_expiration			= 7200;
33
	var $sess_expire_on_close		= FALSE;
34
	var $sess_match_ip				= FALSE;
35
	var $sess_match_useragent		= TRUE;
36
	var $sess_cookie_name			= 'ci_session';
37
	var $cookie_prefix				= '';
38
	var $cookie_path				= '';
39
	var $cookie_domain				= '';
40
	var $cookie_secure				= FALSE;
41
	var $sess_time_to_update		= 300;
42
	var $encryption_key				= '';
43
	var $flashdata_key				= 'flash';
44
	var $time_reference				= 'time';
45
	var $gc_probability				= 5;
46
	var $userdata					= array();
47
	var $CI;
48
	var $now;
49
50
	/**
51
	 * Session Constructor
52
	 *
53
	 * The constructor runs the session routines automatically
54
	 * whenever the class is instantiated.
55
	 */
56
	public function __construct($params = array())
57
	{
58
		log_message('debug', "Session Class Initialized");
59
60
		// Set the super object to a local variable for use throughout the class
61
		$this->CI =& get_instance();
62
63
		// Set all the session preferences, which can either be set
64
		// manually via the $params array above or via the config file
65
		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') as $key)
66
		{
67
			$this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key);
68
		}
69
70
		if ($this->encryption_key == '')
71
		{
72
			show_error('In order to use the Session class you are required to set an encryption key in your config file.');
73
		}
74
75
		// Load the string helper so we can use the strip_slashes() function
76
		$this->CI->load->helper('string');
77
78
		// Do we need encryption? If so, load the encryption class
79
		if ($this->sess_encrypt_cookie == TRUE)
80
		{
81
			$this->CI->load->library('encrypt');
82
		}
83
84
		// Are we using a database?  If so, load it
85
		if ($this->sess_use_database === TRUE AND $this->sess_table_name != '')
86
		{
87
			$this->CI->load->database();
88
		}
89
90
		// Set the "now" time.  Can either be GMT or server time, based on the
91
		// config prefs.  We use this to set the "last activity" time
92
		$this->now = $this->_get_time();
93
94
		// Set the session length. If the session expiration is
95
		// set to zero we'll set the expiration two years from now.
96
		if ($this->sess_expiration == 0)
97
		{
98
			$this->sess_expiration = (60*60*24*365*2);
99
		}
100
101
		// Set the cookie name
102
		$this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name;
103
104
		// Run the Session routine. If a session doesn't exist we'll
105
		// create a new one.  If it does, we'll update it.
106
		if ( ! $this->sess_read())
107
		{
108
			$this->sess_create();
109
		}
110
		else
111
		{
112
			$this->sess_update();
113
		}
114
115
		// Delete 'old' flashdata (from last request)
116
		$this->_flashdata_sweep();
117
118
		// Mark all new flashdata as old (data will be deleted before next request)
119
		$this->_flashdata_mark();
120
121
		// Delete expired sessions if necessary
122
		$this->_sess_gc();
123
124
		log_message('debug', "Session routines successfully run");
125
	}
126
127
	// --------------------------------------------------------------------
128
129
	/**
130
	 * Fetch the current session data if it exists
131
	 *
132
	 * @access	public
133
	 * @return	bool
134
	 */
135
	function sess_read()
136
	{
137
		// Fetch the cookie
138
		$session = $this->CI->input->cookie($this->sess_cookie_name);
139
140
		// No cookie?  Goodbye cruel world!...
141
		if ($session === FALSE)
142
		{
143
			log_message('debug', 'A session cookie was not found.');
144
			return FALSE;
145
		}
146
147
		// Decrypt the cookie data
148
		if ($this->sess_encrypt_cookie == TRUE)
149
		{
150
			$session = $this->CI->encrypt->decode($session);
151
		}
152
		else
153
		{
154
			// encryption was not used, so we need to check the md5 hash
155
			$hash	 = substr($session, strlen($session)-32); // get last 32 chars
156
			$session = substr($session, 0, strlen($session)-32);
157
158
			// Does the md5 hash match?  This is to prevent manipulation of session data in userspace
159
			if ($hash !==  md5($session.$this->encryption_key))
160
			{
161
				log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.');
162
				$this->sess_destroy();
163
				return FALSE;
164
			}
165
		}
166
167
		// Unserialize the session array
168
		$session = $this->_unserialize($session);
169
170
		// Is the session data we unserialized an array with the correct format?
171
		if ( ! is_array($session) OR ! isset($session['session_id']) OR ! isset($session['ip_address']) OR ! isset($session['user_agent']) OR ! isset($session['last_activity']))
172
		{
173
			$this->sess_destroy();
174
			return FALSE;
175
		}
176
177
		// Is the session current?
178
		if (($session['last_activity'] + $this->sess_expiration) < $this->now)
179
		{
180
			$this->sess_destroy();
181
			return FALSE;
182
		}
183
184
		// Does the IP Match?
185
		if ($this->sess_match_ip == TRUE AND $session['ip_address'] != $this->CI->input->ip_address())
186
		{
187
			$this->sess_destroy();
188
			return FALSE;
189
		}
190
191
		// Does the User Agent Match?
192
		if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 120)))
193
		{
194
			$this->sess_destroy();
195
			return FALSE;
196
		}
197
198
		// Is there a corresponding session in the DB?
199
		if ($this->sess_use_database === TRUE)
200
		{
201
			$this->CI->db->where('session_id', $session['session_id']);
202
203
			if ($this->sess_match_ip == TRUE)
204
			{
205
				$this->CI->db->where('ip_address', $session['ip_address']);
206
			}
207
208
			if ($this->sess_match_useragent == TRUE)
209
			{
210
				$this->CI->db->where('user_agent', $session['user_agent']);
211
			}
212
213
			$query = $this->CI->db->get($this->sess_table_name);
214
215
			// No result?  Kill it!
216
			if ($query->num_rows() == 0)
217
			{
218
				$this->sess_destroy();
219
				return FALSE;
220
			}
221
222
			// Is there custom data?  If so, add it to the main session array
223
			$row = $query->row();
224
			if (isset($row->user_data) AND $row->user_data != '')
225
			{
226
				$custom_data = $this->_unserialize($row->user_data);
227
228
				if (is_array($custom_data))
229
				{
230
					foreach ($custom_data as $key => $val)
231
					{
232
						$session[$key] = $val;
233
					}
234
				}
235
			}
236
		}
237
238
		// Session is valid!
239
		$this->userdata = $session;
240
		unset($session);
241
242
		return TRUE;
243
	}
244
245
	// --------------------------------------------------------------------
246
247
	/**
248
	 * Write the session data
249
	 *
250
	 * @access	public
251
	 * @return	void
252
	 */
253
	function sess_write()
254
	{
255
		// Are we saving custom data to the DB?  If not, all we do is update the cookie
256
		if ($this->sess_use_database === FALSE)
257
		{
258
			$this->_set_cookie();
259
			return;
260
		}
261
262
		// set the custom userdata, the session data we will set in a second
263
		$custom_userdata = $this->userdata;
264
		$cookie_userdata = array();
265
266
		// Before continuing, we need to determine if there is any custom data to deal with.
267
		// Let's determine this by removing the default indexes to see if there's anything left in the array
268
		// and set the session data while we're at it
269
		foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
270
		{
271
			unset($custom_userdata[$val]);
272
			$cookie_userdata[$val] = $this->userdata[$val];
273
		}
274
275
		// Did we find any custom data?  If not, we turn the empty array into a string
276
		// since there's no reason to serialize and store an empty array in the DB
277
		if (count($custom_userdata) === 0)
278
		{
279
			$custom_userdata = '';
280
		}
281
		else
282
		{
283
			// Serialize the custom data array so we can store it
284
			$custom_userdata = $this->_serialize($custom_userdata);
285
		}
286
287
		// Run the update query
288
		$this->CI->db->where('session_id', $this->userdata['session_id']);
289
		$this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));
290
291
		// Write the cookie.  Notice that we manually pass the cookie data array to the
292
		// _set_cookie() function. Normally that function will store $this->userdata, but
293
		// in this case that array contains custom data, which we do not want in the cookie.
294
		$this->_set_cookie($cookie_userdata);
295
	}
296
297
	// --------------------------------------------------------------------
298
299
	/**
300
	 * Create a new session
301
	 *
302
	 * @access	public
303
	 * @return	void
304
	 */
305
	function sess_create()
306
	{
307
		$sessid = '';
308
		while (strlen($sessid) < 32)
309
		{
310
			$sessid .= mt_rand(0, mt_getrandmax());
311
		}
312
313
		// To make the session ID even more secure we'll combine it with the user's IP
314
		$sessid .= $this->CI->input->ip_address();
315
316
		$this->userdata = array(
317
							'session_id'	=> md5(uniqid($sessid, TRUE)),
318
							'ip_address'	=> $this->CI->input->ip_address(),
319
							'user_agent'	=> substr($this->CI->input->user_agent(), 0, 120),
320
							'last_activity'	=> $this->now,
321
							'user_data'		=> ''
322
							);
323
324
325
		// Save the data to the DB if needed
326
		if ($this->sess_use_database === TRUE)
327
		{
328
			$this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata));
329
		}
330
331
		// Write the cookie
332
		$this->_set_cookie();
333
	}
334
335
	// --------------------------------------------------------------------
336
337
	/**
338
	 * Update an existing session
339
	 *
340
	 * @access	public
341
	 * @return	void
342
	 */
343
	function sess_update()
344
	{
345
		// We only update the session every five minutes by default
346
		if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
347
		{
348
			return;
349
		}
350
351
		// Save the old session id so we know which record to
352
		// update in the database if we need it
353
		$old_sessid = $this->userdata['session_id'];
354
		$new_sessid = '';
355
		while (strlen($new_sessid) < 32)
356
		{
357
			$new_sessid .= mt_rand(0, mt_getrandmax());
358
		}
359
360
		// To make the session ID even more secure we'll combine it with the user's IP
361
		$new_sessid .= $this->CI->input->ip_address();
362
363
		// Turn it into a hash
364
		$new_sessid = md5(uniqid($new_sessid, TRUE));
365
366
		// Update the session data in the session data array
367
		$this->userdata['session_id'] = $new_sessid;
368
		$this->userdata['last_activity'] = $this->now;
369
370
		// _set_cookie() will handle this for us if we aren't using database sessions
371
		// by pushing all userdata to the cookie.
372
		$cookie_data = NULL;
373
374
		// Update the session ID and last_activity field in the DB if needed
375
		if ($this->sess_use_database === TRUE)
376
		{
377
			// set cookie explicitly to only have our session data
378
			$cookie_data = array();
379
			foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
380
			{
381
				$cookie_data[$val] = $this->userdata[$val];
382
			}
383
384
			$this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
385
		}
386
387
		// Write the cookie
388
		$this->_set_cookie($cookie_data);
389
	}
390
391
	// --------------------------------------------------------------------
392
393
	/**
394
	 * Destroy the current session
395
	 *
396
	 * @access	public
397
	 * @return	void
398
	 */
399
	function sess_destroy()
400
	{
401
		// Kill the session DB row
402
		if ($this->sess_use_database === TRUE && isset($this->userdata['session_id']))
403
		{
404
			$this->CI->db->where('session_id', $this->userdata['session_id']);
405
			$this->CI->db->delete($this->sess_table_name);
406
		}
407
408
		// Kill the cookie
409
		setcookie(
410
					$this->sess_cookie_name,
411
					addslashes(serialize(array())),
412
					($this->now - 31500000),
413
					$this->cookie_path,
414
					$this->cookie_domain,
415
					0
416
				);
417
418
		// Kill session data
419
		$this->userdata = array();
420
	}
421
422
	// --------------------------------------------------------------------
423
424
	/**
425
	 * Fetch a specific item from the session array
426
	 *
427
	 * @access	public
428
	 * @param	string
429
	 * @return	string
430
	 */
431
	function userdata($item)
432
	{
433
		return ( ! isset($this->userdata[$item])) ? FALSE : $this->userdata[$item];
434
	}
435
436
	// --------------------------------------------------------------------
437
438
	/**
439
	 * Fetch all session data
440
	 *
441
	 * @access	public
442
	 * @return	array
443
	 */
444
	function all_userdata()
445
	{
446
		return $this->userdata;
447
	}
448
449
	// --------------------------------------------------------------------
450
451
	/**
452
	 * Add or change data in the "userdata" array
453
	 *
454
	 * @access	public
455
	 * @param	mixed
456
	 * @param	string
457
	 * @return	void
458
	 */
459
	function set_userdata($newdata = array(), $newval = '')
460
	{
461
		if (is_string($newdata))
462
		{
463
			$newdata = array($newdata => $newval);
464
		}
465
466
		if (count($newdata) > 0)
467
		{
468
			foreach ($newdata as $key => $val)
469
			{
470
				$this->userdata[$key] = $val;
471
			}
472
		}
473
474
		$this->sess_write();
475
	}
476
477
	// --------------------------------------------------------------------
478
479
	/**
480
	 * Delete a session variable from the "userdata" array
481
	 *
482
	 * @access	array
483
	 * @return	void
484
	 */
485
	function unset_userdata($newdata = array())
486
	{
487
		if (is_string($newdata))
488
		{
489
			$newdata = array($newdata => '');
490
		}
491
492
		if (count($newdata) > 0)
493
		{
494
			foreach ($newdata as $key => $val)
495
			{
496
				unset($this->userdata[$key]);
497
			}
498
		}
499
500
		$this->sess_write();
501
	}
502
503
	// ------------------------------------------------------------------------
504
505
	/**
506
	 * Add or change flashdata, only available
507
	 * until the next request
508
	 *
509
	 * @access	public
510
	 * @param	mixed
511
	 * @param	string
512
	 * @return	void
513
	 */
514
	function set_flashdata($newdata = array(), $newval = '')
515
	{
516
		if (is_string($newdata))
517
		{
518
			$newdata = array($newdata => $newval);
519
		}
520
521
		if (count($newdata) > 0)
522
		{
523
			foreach ($newdata as $key => $val)
524
			{
525
				$flashdata_key = $this->flashdata_key.':new:'.$key;
526
				$this->set_userdata($flashdata_key, $val);
527
			}
528
		}
529
	}
530
531
	// ------------------------------------------------------------------------
532
533
	/**
534
	 * Keeps existing flashdata available to next request.
535
	 *
536
	 * @access	public
537
	 * @param	string
538
	 * @return	void
539
	 */
540
	function keep_flashdata($key)
541
	{
542
		// 'old' flashdata gets removed.  Here we mark all
543
		// flashdata as 'new' to preserve it from _flashdata_sweep()
544
		// Note the function will return FALSE if the $key
545
		// provided cannot be found
546
		$old_flashdata_key = $this->flashdata_key.':old:'.$key;
547
		$value = $this->userdata($old_flashdata_key);
548
549
		$new_flashdata_key = $this->flashdata_key.':new:'.$key;
550
		$this->set_userdata($new_flashdata_key, $value);
551
	}
552
553
	// ------------------------------------------------------------------------
554
555
	/**
556
	 * Fetch a specific flashdata item from the session array
557
	 *
558
	 * @access	public
559
	 * @param	string
560
	 * @return	string
561
	 */
562
	function flashdata($key)
563
	{
564
		$flashdata_key = $this->flashdata_key.':old:'.$key;
565
		return $this->userdata($flashdata_key);
566
	}
567
568
	// ------------------------------------------------------------------------
569
570
	/**
571
	 * Identifies flashdata as 'old' for removal
572
	 * when _flashdata_sweep() runs.
573
	 *
574
	 * @access	private
575
	 * @return	void
576
	 */
577
	function _flashdata_mark()
578
	{
579
		$userdata = $this->all_userdata();
580
		foreach ($userdata as $name => $value)
581
		{
582
			$parts = explode(':new:', $name);
583
			if (is_array($parts) && count($parts) === 2)
584
			{
585
				$new_name = $this->flashdata_key.':old:'.$parts[1];
586
				$this->set_userdata($new_name, $value);
587
				$this->unset_userdata($name);
588
			}
589
		}
590
	}
591
592
	// ------------------------------------------------------------------------
593
594
	/**
595
	 * Removes all flashdata marked as 'old'
596
	 *
597
	 * @access	private
598
	 * @return	void
599
	 */
600
601
	function _flashdata_sweep()
602
	{
603
		$userdata = $this->all_userdata();
604
		foreach ($userdata as $key => $value)
605
		{
606
			if (strpos($key, ':old:'))
607
			{
608
				$this->unset_userdata($key);
609
			}
610
		}
611
612
	}
613
614
	// --------------------------------------------------------------------
615
616
	/**
617
	 * Get the "now" time
618
	 *
619
	 * @access	private
620
	 * @return	string
621
	 */
622
	function _get_time()
623
	{
624
		if (strtolower($this->time_reference) == 'gmt')
625
		{
626
			$now = time();
627
			$time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now));
628
		}
629
		else
630
		{
631
			$time = time();
632
		}
633
634
		return $time;
635
	}
636
637
	// --------------------------------------------------------------------
638
639
	/**
640
	 * Write the session cookie
641
	 *
642
	 * @access	public
643
	 * @return	void
644
	 */
645
	function _set_cookie($cookie_data = NULL)
646
	{
647
		if (is_null($cookie_data))
648
		{
649
			$cookie_data = $this->userdata;
650
		}
651
652
		// Serialize the userdata for the cookie
653
		$cookie_data = $this->_serialize($cookie_data);
654
655
		if ($this->sess_encrypt_cookie == TRUE)
656
		{
657
			$cookie_data = $this->CI->encrypt->encode($cookie_data);
658
		}
659
		else
660
		{
661
			// if encryption is not used, we provide an md5 hash to prevent userside tampering
662
			$cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
663
		}
664
665
		$expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
666
667
		// Set the cookie
668
		setcookie(
669
					$this->sess_cookie_name,
670
					$cookie_data,
671
					$expire,
672
					$this->cookie_path,
673
					$this->cookie_domain,
674
					$this->cookie_secure
675
				);
676
	}
677
678
	// --------------------------------------------------------------------
679
680
	/**
681
	 * Serialize an array
682
	 *
683
	 * This function first converts any slashes found in the array to a temporary
684
	 * marker, so when it gets unserialized the slashes will be preserved
685
	 *
686
	 * @access	private
687
	 * @param	array
688
	 * @return	string
689
	 */
690
	function _serialize($data)
691
	{
692
		if (is_array($data))
693
		{
694
			foreach ($data as $key => $val)
695
			{
696
				if (is_string($val))
697
				{
698
					$data[$key] = str_replace('\\', '{{slash}}', $val);
699
				}
700
			}
701
		}
702
		else
703
		{
704
			if (is_string($data))
705
			{
706
				$data = str_replace('\\', '{{slash}}', $data);
707
			}
708
		}
709
710
		return serialize($data);
711
	}
712
713
	// --------------------------------------------------------------------
714
715
	/**
716
	 * Unserialize
717
	 *
718
	 * This function unserializes a data string, then converts any
719
	 * temporary slash markers back to actual slashes
720
	 *
721
	 * @access	private
722
	 * @param	array
723
	 * @return	string
724
	 */
725
	function _unserialize($data)
726
	{
727
		$data = @unserialize(strip_slashes($data));
728
729
		if (is_array($data))
730
		{
731
			foreach ($data as $key => $val)
732
			{
733
				if (is_string($val))
734
				{
735
					$data[$key] = str_replace('{{slash}}', '\\', $val);
736
				}
737
			}
738
739
			return $data;
740
		}
741
742
		return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data;
743
	}
744
745
	// --------------------------------------------------------------------
746
747
	/**
748
	 * Garbage collection
749
	 *
750
	 * This deletes expired session rows from database
751
	 * if the probability percentage is met
752
	 *
753
	 * @access	public
754
	 * @return	void
755
	 */
756
	function _sess_gc()
757
	{
758
		if ($this->sess_use_database != TRUE)
759
		{
760
			return;
761
		}
762
763
		srand(time());
764
		if ((rand() % 100) < $this->gc_probability)
765
		{
766
			$expire = $this->now - $this->sess_expiration;
767
768
			$this->CI->db->where("last_activity < {$expire}");
769
			$this->CI->db->delete($this->sess_table_name);
770
771
			log_message('debug', 'Session garbage collection performed.');
772
		}
773
	}
774
775
776
}
777
// END Session Class
778
779
/* End of file Session.php */
780
/* Location: ./system/libraries/Session.php */