00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 if (!class_exists('Set')) {
00037 uses('set');
00038 }
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 class CakeSession extends Object {
00049
00050
00051
00052
00053
00054
00055 var $valid = false;
00056
00057
00058
00059
00060
00061
00062 var $error = false;
00063
00064
00065
00066
00067
00068
00069 var $_userAgent = '';
00070
00071
00072
00073
00074
00075
00076 var $path = '/';
00077
00078
00079
00080
00081
00082
00083 var $lastError = null;
00084
00085
00086
00087
00088
00089
00090 var $security = null;
00091
00092
00093
00094
00095
00096
00097 var $time = false;
00098
00099
00100
00101
00102
00103
00104 var $sessionTime = false;
00105
00106
00107
00108
00109
00110
00111 var $watchKeys = array();
00112
00113
00114
00115
00116
00117
00118 var $id = null;
00119
00120
00121
00122
00123
00124
00125
00126 function __construct($base = null, $start = true) {
00127 if (Configure::read('Session.save') === 'database' && !class_exists('ConnectionManager')) {
00128 App::import('Core', 'ConnectionManager');
00129 }
00130
00131 if (Configure::read('Session.checkAgent') === true || Configure::read('Session.checkAgent') === null) {
00132 if (env('HTTP_USER_AGENT') != null) {
00133 $this->_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt'));
00134 }
00135 }
00136 $this->time = time();
00137
00138 if ($start === true) {
00139 $this->host = env('HTTP_HOST');
00140
00141 if (empty($base) || strpos($base, '?') === 0 || strpos($base, 'index.php') === 0) {
00142 $this->path = '/';
00143 } else {
00144 $this->path = $base;
00145 }
00146
00147 if (strpos($this->host, ':') !== false) {
00148 $this->host = substr($this->host, 0, strpos($this->host, ':'));
00149 }
00150
00151 if (!class_exists('Security')) {
00152 App::import('Core', 'Security');
00153 }
00154
00155 $this->sessionTime = $this->time + (Security::inactiveMins() * Configure::read('Session.timeout'));
00156 $this->security = Configure::read('Security.level');
00157 }
00158 parent::__construct();
00159 }
00160
00161
00162
00163
00164
00165
00166
00167 function start() {
00168 if (function_exists('session_write_close')) {
00169 session_write_close();
00170 }
00171 $this->__initSession();
00172 return $this->__startSession();
00173 }
00174
00175
00176
00177
00178
00179 function started() {
00180 if (isset($_SESSION)) {
00181 return true;
00182 }
00183 return false;
00184 }
00185
00186
00187
00188
00189
00190
00191
00192 function check($name) {
00193 $var = $this->__validateKeys($name);
00194 if (empty($var)) {
00195 return false;
00196 }
00197 $result = Set::extract($_SESSION, $var);
00198 return isset($result);
00199 }
00200
00201
00202
00203
00204
00205
00206 function id($id = null) {
00207 if ($id) {
00208 $this->id = $id;
00209 session_id($this->id);
00210 }
00211 if (isset($_SESSION)) {
00212 return session_id();
00213 } else {
00214 return $this->id;
00215 }
00216 }
00217
00218
00219
00220
00221
00222
00223
00224 function del($name) {
00225 if ($this->check($name)) {
00226 if ($var = $this->__validateKeys($name)) {
00227 if (in_array($var, $this->watchKeys)) {
00228 trigger_error('Deleting session key {' . $var . '}', E_USER_NOTICE);
00229 }
00230 $this->__overwrite($_SESSION, Set::remove($_SESSION, $var));
00231 return ($this->check($var) == false);
00232 }
00233 }
00234 $this->__setError(2, "$name doesn't exist");
00235 return false;
00236 }
00237
00238
00239
00240
00241
00242
00243
00244 function __overwrite(&$old, $new) {
00245 if(!empty($old)) {
00246 foreach ($old as $key => $var) {
00247 if (!isset($new[$key])) {
00248 unset($old[$key]);
00249 }
00250 }
00251 }
00252 foreach ($new as $key => $var) {
00253 $old[$key] = $var;
00254 }
00255 }
00256
00257
00258
00259
00260
00261
00262
00263 function __error($errorNumber) {
00264 if (!is_array($this->error) || !array_key_exists($errorNumber, $this->error)) {
00265 return false;
00266 } else {
00267 return $this->error[$errorNumber];
00268 }
00269 }
00270
00271
00272
00273
00274
00275
00276 function error() {
00277 if ($this->lastError) {
00278 return $this->__error($this->lastError);
00279 } else {
00280 return false;
00281 }
00282 }
00283
00284
00285
00286
00287
00288
00289 function valid() {
00290 if ($this->read('Config')) {
00291 if (Configure::read('Session.checkAgent') === false || $this->_userAgent == $this->read("Config.userAgent") && $this->time <= $this->read("Config.time")) {
00292 if ($this->error === false) {
00293 $this->valid = true;
00294 }
00295 } else {
00296 $this->valid = false;
00297 $this->__setError(1, "Session Highjacking Attempted !!!");
00298 }
00299 }
00300 return $this->valid;
00301 }
00302
00303
00304
00305
00306
00307
00308
00309 function read($name = null) {
00310 if (is_null($name)) {
00311 return $this->__returnSessionVars();
00312 }
00313 if (empty($name)) {
00314 return false;
00315 }
00316 $result = Set::extract($_SESSION, $name);
00317
00318 if (!is_null($result)) {
00319 return $result;
00320 }
00321 $this->__setError(2, "$name doesn't exist");
00322 return null;
00323 }
00324
00325
00326
00327
00328
00329
00330 function __returnSessionVars() {
00331 if (!empty($_SESSION)) {
00332 return $_SESSION;
00333 }
00334 $this->__setError(2, "No Session vars set");
00335 return false;
00336 }
00337
00338
00339
00340
00341
00342
00343 function watch($var) {
00344 $var = $this->__validateKeys($var);
00345 if (empty($var)) {
00346 return false;
00347 }
00348 $this->watchKeys[] = $var;
00349 }
00350
00351
00352
00353
00354
00355
00356 function ignore($var) {
00357 $var = $this->__validateKeys($var);
00358 if (!in_array($var, $this->watchKeys)) {
00359 return;
00360 }
00361 foreach ($this->watchKeys as $i => $key) {
00362 if ($key == $var) {
00363 unset($this->watchKeys[$i]);
00364 $this->watchKeys = array_values($this->watchKeys);
00365 return;
00366 }
00367 }
00368 }
00369
00370
00371
00372
00373
00374
00375
00376
00377 function write($name, $value) {
00378 $var = $this->__validateKeys($name);
00379
00380 if (empty($var)) {
00381 return false;
00382 }
00383 if (in_array($var, $this->watchKeys)) {
00384 trigger_error('Writing session key {' . $var . '}: ' . Debugger::exportVar($value), E_USER_NOTICE);
00385 }
00386 $this->__overwrite($_SESSION, Set::insert($_SESSION, $var, $value));
00387 return (Set::extract($_SESSION, $var) === $value);
00388 }
00389
00390
00391
00392
00393
00394 function destroy() {
00395 $sessionpath = session_save_path();
00396 if (empty($sessionpath)) {
00397 $sessionpath = "/tmp";
00398 }
00399
00400 if (isset($_COOKIE[session_name()])) {
00401 setcookie(Configure::read('Session.cookie'), '', time() - 42000, $this->path);
00402 }
00403
00404 $_SESSION = array();
00405 $file = $sessionpath . DS . "sess_" . session_id();
00406 @session_destroy();
00407 @unlink ($file);
00408 $this->__construct($this->path);
00409 $this->renew();
00410 }
00411
00412
00413
00414
00415
00416 function __initSession() {
00417 switch($this->security) {
00418 case 'high':
00419 $this->cookieLifeTime = 0;
00420 if (function_exists('ini_set')) {
00421 ini_set('session.referer_check', $this->host);
00422 }
00423 break;
00424 case 'medium':
00425 $this->cookieLifeTime = 7 * 86400;
00426 if (function_exists('ini_set')) {
00427 ini_set('session.referer_check', $this->host);
00428 }
00429 break;
00430 case 'low':
00431 default:
00432 $this->cookieLifeTime = 788940000;
00433 break;
00434 }
00435
00436 switch(Configure::read('Session.save')) {
00437 case 'cake':
00438 if (!isset($_SESSION)) {
00439 if (function_exists('ini_set')) {
00440 ini_set('session.use_trans_sid', 0);
00441 ini_set('url_rewriter.tags', '');
00442 ini_set('session.serialize_handler', 'php');
00443 ini_set('session.use_cookies', 1);
00444 ini_set('session.name', Configure::read('Session.cookie'));
00445 ini_set('session.cookie_lifetime', $this->cookieLifeTime);
00446 ini_set('session.cookie_path', $this->path);
00447 ini_set('session.auto_start', 0);
00448 ini_set('session.save_path', TMP . 'sessions');
00449 }
00450 }
00451 break;
00452 case 'database':
00453 if (!isset($_SESSION)) {
00454 if (Configure::read('Session.table') === null) {
00455 trigger_error(__("You must set the all Configure::write('Session.*') in core.php to use database storage"), E_USER_WARNING);
00456 exit();
00457 } elseif (Configure::read('Session.database') === null) {
00458 Configure::write('Session.database', 'default');
00459 }
00460 if (function_exists('ini_set')) {
00461 ini_set('session.use_trans_sid', 0);
00462 ini_set('url_rewriter.tags', '');
00463 ini_set('session.save_handler', 'user');
00464 ini_set('session.serialize_handler', 'php');
00465 ini_set('session.use_cookies', 1);
00466 ini_set('session.name', Configure::read('Session.cookie'));
00467 ini_set('session.cookie_lifetime', $this->cookieLifeTime);
00468 ini_set('session.cookie_path', $this->path);
00469 ini_set('session.auto_start', 0);
00470 }
00471 }
00472 session_set_save_handler(array('CakeSession','__open'),
00473 array('CakeSession', '__close'),
00474 array('CakeSession', '__read'),
00475 array('CakeSession', '__write'),
00476 array('CakeSession', '__destroy'),
00477 array('CakeSession', '__gc'));
00478 break;
00479 case 'php':
00480 if (!isset($_SESSION)) {
00481 if (function_exists('ini_set')) {
00482 ini_set('session.use_trans_sid', 0);
00483 ini_set('session.name', Configure::read('Session.cookie'));
00484 ini_set('session.cookie_lifetime', $this->cookieLifeTime);
00485 ini_set('session.cookie_path', $this->path);
00486 }
00487 }
00488 break;
00489 case 'cache':
00490 if (!isset($_SESSION)) {
00491 if (!class_exists('Cache')) {
00492 uses('Cache');
00493 }
00494 if (function_exists('ini_set')) {
00495 ini_set('session.use_trans_sid', 0);
00496 ini_set('url_rewriter.tags', '');
00497 ini_set('session.save_handler', 'user');
00498 ini_set('session.use_cookies', 1);
00499 ini_set('session.name', Configure::read('Session.cookie'));
00500 ini_set('session.cookie_lifetime', $this->cookieLifeTime);
00501 ini_set('session.cookie_path', $this->path);
00502 }
00503 }
00504 session_set_save_handler(array('CakeSession','__open'),
00505 array('CakeSession', '__close'),
00506 array('Cache', 'read'),
00507 array('Cache', 'write'),
00508 array('Cache', 'delete'),
00509 array('CakeSession', '__gc'));
00510 break;
00511 default:
00512 if (!isset($_SESSION)) {
00513 $config = CONFIGS . Configure::read('Session.save') . '.php';
00514
00515 if (is_file($config)) {
00516 require_once ($config);
00517 }
00518 }
00519 break;
00520 }
00521 }
00522
00523
00524
00525
00526
00527 function __startSession() {
00528 if (headers_sent()) {
00529 if (!isset($_SESSION)) {
00530 $_SESSION = array();
00531 }
00532 return false;
00533 } elseif (!isset($_SESSION)) {
00534 session_cache_limiter ("must-revalidate");
00535 session_start();
00536 header ('P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"');
00537 return true;
00538 } else {
00539 session_start();
00540 return true;
00541 }
00542 }
00543
00544
00545
00546
00547
00548 function _checkValid() {
00549 if ($this->read('Config')) {
00550 if (Configure::read('Session.checkAgent') === false || $this->_userAgent == $this->read("Config.userAgent") && $this->time <= $this->read("Config.time")) {
00551 $time = $this->read("Config.time");
00552 $this->write("Config.time", $this->sessionTime);
00553
00554 if (Configure::read('Security.level') === 'high') {
00555 $check = $this->read("Config.timeout");
00556 $check = $check - 1;
00557 $this->write("Config.timeout", $check);
00558
00559 if (time() > ($time - (Security::inactiveMins() * Configure::read('Session.timeout')) + 2) || $check < 1) {
00560 $this->renew();
00561 $this->write('Config.timeout', 10);
00562 }
00563 }
00564 $this->valid = true;
00565 } else {
00566 $this->destroy();
00567 $this->valid = false;
00568 $this->__setError(1, "Session Highjacking Attempted !!!");
00569 }
00570 } else {
00571 srand ((double)microtime() * 1000000);
00572 $this->write("Config.userAgent", $this->_userAgent);
00573 $this->write("Config.time", $this->sessionTime);
00574 $this->write('Config.rand', rand());
00575 $this->write('Config.timeout', 10);
00576 $this->valid = true;
00577 $this->__setError(1, "Session is valid");
00578 }
00579 }
00580
00581
00582
00583
00584
00585 function __regenerateId() {
00586 $oldSessionId = session_id();
00587 if ($oldSessionId) {
00588 $sessionpath = session_save_path();
00589 if (empty($sessionpath)) {
00590 $sessionpath = "/tmp";
00591 }
00592 if (isset($_COOKIE[session_name()])) {
00593 setcookie(Configure::read('Session.cookie'), '', time() - 42000, $this->path);
00594 }
00595 session_regenerate_id();
00596 $newSessid = session_id();
00597
00598 if (function_exists('session_write_close')) {
00599 session_write_close();
00600 }
00601 $this->__initSession();
00602 session_id($oldSessionId);
00603 session_start();
00604 session_destroy();
00605 $file = $sessionpath . DS . "sess_$oldSessionId";
00606 @unlink($file);
00607 $this->__initSession();
00608 session_id($newSessid);
00609 session_start();
00610 }
00611 }
00612
00613
00614
00615
00616
00617 function renew() {
00618 $this->__regenerateId();
00619 }
00620
00621
00622
00623
00624
00625
00626
00627
00628 function __validateKeys($name) {
00629 if (is_string($name) && preg_match("/^[ 0-9a-zA-Z._-]*$/", $name)) {
00630 return $name;
00631 }
00632 $this->__setError(3, "$name is not a string");
00633 return false;
00634 }
00635
00636
00637
00638
00639
00640
00641
00642 function __setError($errorNumber, $errorMessage) {
00643 if ($this->error === false) {
00644 $this->error = array();
00645 }
00646 $this->error[$errorNumber] = $errorMessage;
00647 $this->lastError = $errorNumber;
00648 }
00649
00650
00651
00652
00653
00654
00655 function __open() {
00656 return true;
00657 }
00658
00659
00660
00661
00662
00663
00664 function __close() {
00665 $probability = mt_rand(1, 150);
00666 if ($probability <= 3) {
00667 switch(Configure::read('Session.save')) {
00668 case 'cache':
00669 Cache::gc();
00670 break;
00671 default:
00672 CakeSession::__gc();
00673 break;
00674 }
00675 }
00676 return true;
00677 }
00678
00679
00680
00681
00682
00683
00684
00685 function __read($key) {
00686 $db =& ConnectionManager::getDataSource(Configure::read('Session.database'));
00687 $table = $db->fullTableName(Configure::read('Session.table'), false);
00688 $row = $db->query("SELECT " . $db->name($table.'.data') . " FROM " . $db->name($table) . " WHERE " . $db->name($table.'.id') . " = " . $db->value($key), false);
00689
00690 if ($row && !isset($row[0][$table]) && isset($row[0][0])) {
00691 $table = 0;
00692 }
00693
00694 if ($row && $row[0][$table]['data']) {
00695 return $row[0][$table]['data'];
00696 } else {
00697 return false;
00698 }
00699 }
00700
00701
00702
00703
00704
00705
00706
00707
00708 function __write($key, $value) {
00709 $db =& ConnectionManager::getDataSource(Configure::read('Session.database'));
00710 $table = $db->fullTableName(Configure::read('Session.table'));
00711
00712 switch(Configure::read('Security.level')) {
00713 case 'high':
00714 $factor = 10;
00715 break;
00716 case 'medium':
00717 $factor = 100;
00718 break;
00719 case 'low':
00720 $factor = 300;
00721 break;
00722 default:
00723 $factor = 10;
00724 break;
00725 }
00726 $expires = time() + Configure::read('Session.timeout') * $factor;
00727 $row = $db->query("SELECT COUNT(id) AS count FROM " . $db->name($table) . " WHERE "
00728 . $db->name('id') . " = "
00729 . $db->value($key), false);
00730
00731 if ($row[0][0]['count'] > 0) {
00732 $db->execute("UPDATE " . $db->name($table) . " SET " . $db->name('data') . " = "
00733 . $db->value($value) . ", " . $db->name('expires') . " = "
00734 . $db->value($expires) . " WHERE " . $db->name('id') . " = "
00735 . $db->value($key));
00736 } else {
00737 $db->execute("INSERT INTO " . $db->name($table) . " (" . $db->name('data') . ","
00738 . $db->name('expires') . "," . $db->name('id')
00739 . ") VALUES (" . $db->value($value) . ", " . $db->value($expires) . ", "
00740 . $db->value($key) . ")");
00741 }
00742 return true;
00743 }
00744
00745
00746
00747
00748
00749
00750
00751 function __destroy($key) {
00752 $db =& ConnectionManager::getDataSource(Configure::read('Session.database'));
00753 $table = $db->fullTableName(Configure::read('Session.table'));
00754 $db->execute("DELETE FROM " . $db->name($table) . " WHERE " . $db->name($table.'.id') . " = " . $db->value($key));
00755 return true;
00756 }
00757
00758
00759
00760
00761
00762
00763
00764 function __gc($expires = null) {
00765 $db =& ConnectionManager::getDataSource(Configure::read('Session.database'));
00766 $table = $db->fullTableName(Configure::read('Session.table'));
00767 $db->execute("DELETE FROM " . $db->name($table) . " WHERE " . $db->name($table.'.expires') . " < ". $db->value(time()));
00768 return true;
00769 }
00770 }
00771 ?>