1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
29: 30: 31: 32:
33: if (!class_exists('Set')) {
34: require LIBS . 'set.php';
35: }
36: if (!class_exists('Security')) {
37: require LIBS . 'security.php';
38: }
39: 40: 41: 42: 43: 44: 45: 46: 47:
48: class CakeSession extends Object {
49: 50: 51: 52: 53: 54:
55: var $valid = false;
56: 57: 58: 59: 60: 61:
62: var $error = false;
63: 64: 65: 66: 67: 68:
69: var $_userAgent = '';
70: 71: 72: 73: 74: 75:
76: var $path = '/';
77: 78: 79: 80: 81: 82:
83: var $lastError = null;
84: 85: 86: 87: 88: 89:
90: var $security = null;
91: 92: 93: 94: 95: 96:
97: var $time = false;
98: 99: 100: 101: 102: 103:
104: var $sessionTime = false;
105: 106: 107: 108: 109: 110:
111: var $watchKeys = array();
112: 113: 114: 115: 116: 117:
118: var $id = null;
119: 120: 121: 122: 123: 124:
125: var $host = null;
126: 127: 128: 129: 130: 131: 132:
133: function __construct($base = null, $start = true) {
134: if (Configure::read('Session.save') === 'database' && !class_exists('ConnectionManager')) {
135: App::import('Core', 'ConnectionManager');
136: }
137:
138: if (Configure::read('Session.checkAgent') === true || Configure::read('Session.checkAgent') === null) {
139: if (env('HTTP_USER_AGENT') != null) {
140: $this->_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt'));
141: }
142: }
143: $this->time = time();
144:
145: if ($start === true) {
146: if (!empty($base)) {
147: $this->path = $base;
148: if (strpos($base, 'index.php') !== false) {
149: $this->path = str_replace('index.php', '', $base);
150: }
151: if (strpos($base, '?') !== false) {
152: $this->path = str_replace('?', '', $base);
153: }
154: }
155: $this->host = env('HTTP_HOST');
156:
157: if (strpos($this->host, ':') !== false) {
158: $this->host = substr($this->host, 0, strpos($this->host, ':'));
159: }
160: }
161: if (isset($_SESSION) || $start === true) {
162: if (!class_exists('Security')) {
163: App::import('Core', 'Security');
164: }
165: $this->sessionTime = $this->time + (Security::inactiveMins() * Configure::read('Session.timeout'));
166: $this->security = Configure::read('Security.level');
167: }
168: parent::__construct();
169: }
170: 171: 172: 173: 174: 175:
176: function start() {
177: if ($this->started()) {
178: return true;
179: }
180: if (function_exists('session_write_close')) {
181: session_write_close();
182: }
183: $this->__initSession();
184: $this->__startSession();
185: return $this->started();
186: }
187: 188: 189: 190: 191: 192:
193: function started() {
194: if (isset($_SESSION) && session_id()) {
195: return true;
196: }
197: return false;
198: }
199: 200: 201: 202: 203: 204: 205:
206: function check($name) {
207: $var = $this->__validateKeys($name);
208: if (empty($var)) {
209: return false;
210: }
211: $result = Set::extract($_SESSION, $var);
212: return isset($result);
213: }
214: 215: 216: 217: 218: 219: 220:
221: function id($id = null) {
222: if ($id) {
223: $this->id = $id;
224: session_id($this->id);
225: }
226: if ($this->started()) {
227: return session_id();
228: } else {
229: return $this->id;
230: }
231: }
232: 233: 234: 235: 236: 237: 238:
239: function del($name) {
240: if ($this->check($name)) {
241: if ($var = $this->__validateKeys($name)) {
242: if (in_array($var, $this->watchKeys)) {
243: trigger_error('Deleting session key {' . $var . '}', E_USER_NOTICE);
244: }
245: $this->__overwrite($_SESSION, Set::remove($_SESSION, $var));
246: return ($this->check($var) == false);
247: }
248: }
249: $this->__setError(2, "$name doesn't exist");
250: return false;
251: }
252: 253: 254: 255: 256: 257: 258:
259: function __overwrite(&$old, $new) {
260: if (!empty($old)) {
261: foreach ($old as $key => $var) {
262: if (!isset($new[$key])) {
263: unset($old[$key]);
264: }
265: }
266: }
267: foreach ($new as $key => $var) {
268: $old[$key] = $var;
269: }
270: }
271: 272: 273: 274: 275: 276: 277:
278: function __error($errorNumber) {
279: if (!is_array($this->error) || !array_key_exists($errorNumber, $this->error)) {
280: return false;
281: } else {
282: return $this->error[$errorNumber];
283: }
284: }
285: 286: 287: 288: 289: 290:
291: function error() {
292: if ($this->lastError) {
293: return $this->__error($this->lastError);
294: } else {
295: return false;
296: }
297: }
298: 299: 300: 301: 302: 303:
304: function valid() {
305: if ($this->read('Config')) {
306: if ((Configure::read('Session.checkAgent') === false || $this->_userAgent == $this->read('Config.userAgent')) && $this->time <= $this->read('Config.time')) {
307: if ($this->error === false) {
308: $this->valid = true;
309: }
310: } else {
311: $this->valid = false;
312: $this->__setError(1, 'Session Highjacking Attempted !!!');
313: }
314: }
315: return $this->valid;
316: }
317: 318: 319: 320: 321: 322: 323:
324: function read($name = null) {
325: if (is_null($name)) {
326: return $this->__returnSessionVars();
327: }
328: if (empty($name)) {
329: return false;
330: }
331: $result = Set::extract($_SESSION, $name);
332:
333: if (!is_null($result)) {
334: return $result;
335: }
336: $this->__setError(2, "$name doesn't exist");
337: return null;
338: }
339: 340: 341: 342: 343: 344:
345: function __returnSessionVars() {
346: if (!empty($_SESSION)) {
347: return $_SESSION;
348: }
349: $this->__setError(2, "No Session vars set");
350: return false;
351: }
352: 353: 354: 355: 356: 357: 358:
359: function watch($var) {
360: $var = $this->__validateKeys($var);
361: if (empty($var)) {
362: return false;
363: }
364: if (!in_array($var, $this->watchKeys, true)) {
365: $this->watchKeys[] = $var;
366: }
367: }
368: 369: 370: 371: 372: 373: 374:
375: function ignore($var) {
376: $var = $this->__validateKeys($var);
377: if (!in_array($var, $this->watchKeys)) {
378: return;
379: }
380: foreach ($this->watchKeys as $i => $key) {
381: if ($key == $var) {
382: unset($this->watchKeys[$i]);
383: $this->watchKeys = array_values($this->watchKeys);
384: return;
385: }
386: }
387: }
388: 389: 390: 391: 392: 393: 394: 395:
396: function write($name, $value) {
397: $var = $this->__validateKeys($name);
398:
399: if (empty($var)) {
400: return false;
401: }
402: if (in_array($var, $this->watchKeys)) {
403: trigger_error('Writing session key {' . $var . '}: ' . Debugger::exportVar($value), E_USER_NOTICE);
404: }
405: $this->__overwrite($_SESSION, Set::insert($_SESSION, $var, $value));
406: return (Set::extract($_SESSION, $var) === $value);
407: }
408: 409: 410: 411: 412: 413:
414: function destroy() {
415: $_SESSION = array();
416: $this->__construct($this->path);
417: $this->start();
418: $this->renew();
419: $this->_checkValid();
420: }
421: 422: 423: 424: 425:
426: function __initSession() {
427: $iniSet = function_exists('ini_set');
428:
429: if ($iniSet && env('HTTPS')) {
430: ini_set('session.cookie_secure', 1);
431: }
432:
433: switch ($this->security) {
434: case 'high':
435: $this->cookieLifeTime = 0;
436: if ($iniSet) {
437: ini_set('session.referer_check', $this->host);
438: }
439: break;
440: case 'medium':
441: $this->cookieLifeTime = 7 * 86400;
442: if ($iniSet) {
443: ini_set('session.referer_check', $this->host);
444: }
445: break;
446: case 'low':
447: default:
448: $this->cookieLifeTime = 788940000;
449: break;
450: }
451:
452: switch (Configure::read('Session.save')) {
453: case 'cake':
454: if (empty($_SESSION)) {
455: if ($iniSet) {
456: ini_set('session.use_trans_sid', 0);
457: ini_set('url_rewriter.tags', '');
458: ini_set('session.serialize_handler', 'php');
459: ini_set('session.use_cookies', 1);
460: ini_set('session.name', Configure::read('Session.cookie'));
461: ini_set('session.cookie_lifetime', $this->cookieLifeTime);
462: ini_set('session.cookie_path', $this->path);
463: ini_set('session.auto_start', 0);
464: ini_set('session.save_path', TMP . 'sessions');
465: }
466: }
467: break;
468: case 'database':
469: if (empty($_SESSION)) {
470: if (Configure::read('Session.table') === null) {
471: trigger_error(__("You must set the all Configure::write('Session.*') in core.php to use database storage"), E_USER_WARNING);
472: exit();
473: } elseif (Configure::read('Session.database') === null) {
474: Configure::write('Session.database', 'default');
475: }
476: if ($iniSet) {
477: ini_set('session.use_trans_sid', 0);
478: ini_set('url_rewriter.tags', '');
479: ini_set('session.save_handler', 'user');
480: ini_set('session.serialize_handler', 'php');
481: ini_set('session.use_cookies', 1);
482: ini_set('session.name', Configure::read('Session.cookie'));
483: ini_set('session.cookie_lifetime', $this->cookieLifeTime);
484: ini_set('session.cookie_path', $this->path);
485: ini_set('session.auto_start', 0);
486: }
487: }
488: session_set_save_handler(
489: array('CakeSession','__open'),
490: array('CakeSession', '__close'),
491: array('CakeSession', '__read'),
492: array('CakeSession', '__write'),
493: array('CakeSession', '__destroy'),
494: array('CakeSession', '__gc'));
495: break;
496: case 'php':
497: if (empty($_SESSION)) {
498: if ($iniSet) {
499: ini_set('session.use_trans_sid', 0);
500: ini_set('session.name', Configure::read('Session.cookie'));
501: ini_set('session.cookie_lifetime', $this->cookieLifeTime);
502: ini_set('session.cookie_path', $this->path);
503: }
504: }
505: break;
506: case 'cache':
507: if (empty($_SESSION)) {
508: if (!class_exists('Cache')) {
509: uses('Cache');
510: }
511: if ($iniSet) {
512: ini_set('session.use_trans_sid', 0);
513: ini_set('url_rewriter.tags', '');
514: ini_set('session.save_handler', 'user');
515: ini_set('session.use_cookies', 1);
516: ini_set('session.name', Configure::read('Session.cookie'));
517: ini_set('session.cookie_lifetime', $this->cookieLifeTime);
518: ini_set('session.cookie_path', $this->path);
519: }
520: }
521: session_set_save_handler(
522: array('CakeSession','__open'),
523: array('CakeSession', '__close'),
524: array('Cache', 'read'),
525: array('Cache', 'write'),
526: array('Cache', 'delete'),
527: array('Cache', 'gc'));
528: break;
529: default:
530: $config = CONFIGS . Configure::read('Session.save') . '.php';
531:
532: if (is_file($config)) {
533: require($config);
534: }
535: break;
536: }
537: }
538: 539: 540: 541: 542:
543: function __startSession() {
544: if (headers_sent()) {
545: if (empty($_SESSION)) {
546: $_SESSION = array();
547: }
548: return false;
549: } elseif (!isset($_SESSION)) {
550: session_cache_limiter ("must-revalidate");
551: session_start();
552: header ('P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"');
553: return true;
554: } else {
555: session_start();
556: return true;
557: }
558: }
559: 560: 561: 562: 563: 564:
565: function _checkValid() {
566: if ($this->read('Config')) {
567: if ((Configure::read('Session.checkAgent') === false || $this->_userAgent == $this->read('Config.userAgent')) && $this->time <= $this->read('Config.time')) {
568: $time = $this->read('Config.time');
569: $this->write('Config.time', $this->sessionTime);
570:
571: if (Configure::read('Security.level') === 'high') {
572: $check = $this->read('Config.timeout');
573: $check = $check - 1;
574: $this->write('Config.timeout', $check);
575:
576: if (time() > ($time - (Security::inactiveMins() * Configure::read('Session.timeout')) + 2) || $check < 1) {
577: $this->renew();
578: $this->write('Config.timeout', 10);
579: }
580: }
581: $this->valid = true;
582: } else {
583: $this->destroy();
584: $this->valid = false;
585: $this->__setError(1, 'Session Highjacking Attempted !!!');
586: }
587: } else {
588: $this->write('Config.userAgent', $this->_userAgent);
589: $this->write('Config.time', $this->sessionTime);
590: $this->write('Config.timeout', 10);
591: $this->valid = true;
592: $this->__setError(1, 'Session is valid');
593: }
594: }
595: 596: 597: 598: 599: 600:
601: function __regenerateId() {
602: $oldSessionId = session_id();
603: if ($oldSessionId) {
604: if (session_id() != ''|| isset($_COOKIE[session_name()])) {
605: setcookie(Configure::read('Session.cookie'), '', time() - 42000, $this->path);
606: }
607: session_regenerate_id(true);
608: if (PHP_VERSION < 5.1) {
609: $sessionPath = session_save_path();
610: if (empty($sessionPath)) {
611: $sessionPath = '/tmp';
612: }
613: $newSessid = session_id();
614:
615: if (function_exists('session_write_close')) {
616: session_write_close();
617: }
618: $this->__initSession();
619: session_id($oldSessionId);
620: session_start();
621: session_destroy();
622: $file = $sessionPath . DS . 'sess_' . $oldSessionId;
623: @unlink($file);
624: $this->__initSession();
625: session_id($newSessid);
626: session_start();
627: }
628: }
629: }
630: 631: 632: 633: 634:
635: function renew() {
636: $this->__regenerateId();
637: }
638: 639: 640: 641: 642: 643: 644: 645:
646: function __validateKeys($name) {
647: if (is_string($name) && preg_match("/^[ 0-9a-zA-Z._-]*$/", $name)) {
648: return $name;
649: }
650: $this->__setError(3, "$name is not a string");
651: return false;
652: }
653: 654: 655: 656: 657: 658: 659: 660:
661: function __setError($errorNumber, $errorMessage) {
662: if ($this->error === false) {
663: $this->error = array();
664: }
665: $this->error[$errorNumber] = $errorMessage;
666: $this->lastError = $errorNumber;
667: }
668: 669: 670: 671: 672: 673:
674: function __open() {
675: return true;
676: }
677: 678: 679: 680: 681: 682:
683: function __close() {
684: $probability = mt_rand(1, 150);
685: if ($probability <= 3) {
686: switch (Configure::read('Session.save')) {
687: case 'cache':
688: Cache::gc();
689: break;
690: default:
691: CakeSession::__gc();
692: break;
693: }
694: }
695: return true;
696: }
697: 698: 699: 700: 701: 702: 703:
704: function __read($key) {
705: $db =& ConnectionManager::getDataSource(Configure::read('Session.database'));
706: $table = $db->fullTableName(Configure::read('Session.table'), false);
707: $row = $db->query("SELECT " . $db->name($table.'.data') . " FROM " . $db->name($table) . " WHERE " . $db->name($table.'.id') . " = " . $db->value($key), false);
708:
709: if ($row && !isset($row[0][$table]) && isset($row[0][0])) {
710: $table = 0;
711: }
712:
713: if ($row && $row[0][$table]['data']) {
714: return $row[0][$table]['data'];
715: } else {
716: return false;
717: }
718: }
719: 720: 721: 722: 723: 724: 725: 726:
727: function __write($key, $value) {
728: $db =& ConnectionManager::getDataSource(Configure::read('Session.database'));
729: $table = $db->fullTableName(Configure::read('Session.table'));
730:
731: switch (Configure::read('Security.level')) {
732: case 'high':
733: $factor = 10;
734: break;
735: case 'medium':
736: $factor = 100;
737: break;
738: case 'low':
739: $factor = 300;
740: break;
741: default:
742: $factor = 10;
743: break;
744: }
745: $expires = time() + Configure::read('Session.timeout') * $factor;
746: $row = $db->query("SELECT COUNT(id) AS count FROM " . $db->name($table) . " WHERE "
747: . $db->name('id') . " = "
748: . $db->value($key), false);
749:
750: if ($row[0][0]['count'] > 0) {
751: $db->execute("UPDATE " . $db->name($table) . " SET " . $db->name('data') . " = "
752: . $db->value($value) . ", " . $db->name('expires') . " = "
753: . $db->value($expires) . " WHERE " . $db->name('id') . " = "
754: . $db->value($key));
755: } else {
756: $db->execute("INSERT INTO " . $db->name($table) . " (" . $db->name('data') . ","
757: . $db->name('expires') . "," . $db->name('id')
758: . ") VALUES (" . $db->value($value) . ", " . $db->value($expires) . ", "
759: . $db->value($key) . ")");
760: }
761: return true;
762: }
763: 764: 765: 766: 767: 768: 769:
770: function __destroy($key) {
771: $db =& ConnectionManager::getDataSource(Configure::read('Session.database'));
772: $table = $db->fullTableName(Configure::read('Session.table'));
773: $db->execute("DELETE FROM " . $db->name($table) . " WHERE " . $db->name($table.'.id') . " = " . $db->value($key));
774: return true;
775: }
776: 777: 778: 779: 780: 781: 782:
783: function __gc($expires = null) {
784: $db =& ConnectionManager::getDataSource(Configure::read('Session.database'));
785: $table = $db->fullTableName(Configure::read('Session.table'));
786: $db->execute("DELETE FROM " . $db->name($table) . " WHERE " . $db->name($table.'.expires') . " < ". $db->value(time()));
787: return true;
788: }
789: }
790: ?>