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