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: namespace Flea;
28:
29: 30: 31: 32: 33:
34: class LoginTableName {
35:
36: 37: 38: 39: 40:
41: public static $TABLE_NAME_DATAS = 'login_datas';
42:
43: 44: 45: 46:
47: public static $TABLE_NAME_USERS = 'login_users';
48:
49: 50: 51: 52:
53: public static $TABLE_NAME_LOGS = 'login_logs';
54:
55: }
56:
57: 58: 59: 60: 61:
62: class LoginUser {
63:
64: 65: 66: 67: 68:
69: public static $ROLE_BASIC = 1;
70:
71: 72: 73: 74: 75:
76: public static $ROLE_ADMIN = 2;
77: private $_db;
78: private $_email;
79:
80: 81: 82: 83: 84:
85: public function getEmail() {
86: return $this->_email;
87: }
88:
89: private $_token;
90:
91: 92: 93: 94: 95:
96: public function getToken() {
97: return $this->_token;
98: }
99:
100: private $_role;
101:
102: 103: 104: 105: 106:
107: public function getRole() {
108: return $this->_role;
109: }
110:
111: 112: 113: 114: 115:
116: public function __construct($db) {
117: $this->_db = $db;
118: }
119:
120: 121: 122: 123: 124: 125: 126:
127: public function init($email, $token, $role = 1) {
128: $this->_email = $email;
129: $this->_token = $token;
130: $this->_role = $role;
131: }
132:
133: private $_datas;
134:
135: 136: 137: 138: 139:
140: public function getDatas() {
141: if ($this->_datas === null) {
142: $this->_datas = new DataList(true);
143:
144: $query = SqlQuery::getTemp(SqlQuery::$TYPE_SELECT);
145: $where = array('user_email' => $this->getEmail());
146: $query->initSelect('key, value', '`' . LoginTableName::$TABLE_NAME_DATAS . '`', $where);
147:
148: foreach ($this->_db->fetchAll($query) as $row) {
149: $this->_datas->add($row['value'], $row['key']);
150: }
151: }
152: return $this->_datas;
153: }
154:
155: }
156:
157: 158: 159: 160: 161:
162: class Login {
163:
164: private static $_INSTANCE = array();
165: private static $_HASH_ALGO = 'whirlpool';
166: private static $_IS_SESSION_STARTED = false;
167:
168: 169: 170:
171: private $_db;
172: private $_loginFormHelper = null;
173: private $_user = null;
174:
175: 176: 177: 178: 179:
180: public function isConnected() {
181: if (isset($_SESSION['login_token'])) {
182: if ($this->_user === null) {
183: $where = array('token' => $_SESSION['login_token']);
184: $query = SqlQuery::getTemp(SqlQuery::$TYPE_SELECT);
185: $query->initSelect('*', LoginTableName::$TABLE_NAME_USERS, $where);
186: $rows = $this->_db->fetchAll($query);
187: if (count($rows) < 1) {
188: return false;
189: }
190: }
191: return true;
192: }
193: return false;
194: }
195:
196: 197: 198: 199: 200:
201: public function getUserConnected() {
202: if (!$this->isConnected()) {
203:
204: return new ValueObject(null, true, array('You are don\'t connected'));
205: }
206:
207: if ($this->_user == null) {
208: $query = SqlQuery::getTemp();
209: $where = array('token' => $_SESSION['login_token']);
210: $query->initSelect('*', LoginTableName::$TABLE_NAME_USERS, $where);
211: $rows = $this->_db->fetchAll($query);
212: if (count($rows) < 1) {
213: return new ValueObject(null, true, array('Connection data corrupted'));
214: }
215:
216: $this->_user = new LoginUser($this->_db);
217: $this->_user->init($rows[0]['email'], $rows[0]['token'], $rows[0]['role']);
218: }
219:
220: return new ValueObject($this->_user);
221: ;
222: }
223:
224: 225: 226: 227: 228:
229: public function getLoginFormHelper() {
230: if ($this->_loginFormHelper === null) {
231: include_once _SYSTEM_DIRECTORY . 'helpers/miscellaneous/LoginFormHelper.php';
232: $this->_loginFormHelper = new LoginFormHelper($this);
233: }
234: return $this->_loginFormHelper;
235: }
236:
237: 238: 239: 240: 241: 242: 243:
244: public function passEncrypt($realPass, $email) {
245: return hash(self::$_HASH_ALGO, $realPass . $email);
246: }
247:
248: 249: 250: 251: 252:
253: public function hasUsersInList() {
254: $query = SqlQuery::getTemp(SqlQuery::$TYPE_SELECT);
255: $query->initSelect('COUNT(*)', LoginTableName::$TABLE_NAME_USERS);
256: return $this->_db->count($query) > 0;
257: }
258:
259: 260: 261: 262: 263: 264: 265: 266: 267:
268: public function getUserByEMail($email) {
269: $userConnectedVO = $this->getUserConnected();
270: if ($userConnectedVO->error) {
271: return new ValueObject(null, true, $userConnectedVO->errorList);
272: } else if ($userConnectedVO->content->getRole() != LoginUser::$ROLE_ADMIN) {
273: return new ValueObject(null, true, array('Only admin can see others user with her email'));
274: }
275:
276: $tnu = LoginTableName::$TABLE_NAME_USERS;
277:
278: $query = SqlQuery::getTemp(SqlQuery::$TYPE_SELECT);
279: $query->initSelect('email, role', $tnu, array('email' => $email));
280: $rows = $this->_db->fetchAll($query);
281: if (count($rows) < 1) {
282: return new ValueObject(null, true, array('No users have this email'));
283: }
284:
285: $user = new LoginUser($this->_db);
286: $user->init($rows[0]['email'], 'null', $rows[0]['role']);
287: return new ValueObject($user);
288: }
289:
290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322:
323: public function getUserList($dataKey = null, $dataValue = null) {
324: $list = array();
325:
326: $userConnectedVO = $this->getUserConnected();
327: if ($userConnectedVO->error) {
328: return new ValueObject($list, true, $userConnectedVO->errorList);
329: } else if ($userConnectedVO->content->getRole() != LoginUser::$ROLE_ADMIN) {
330: return new ValueObject($list, true, array('Only admin can see others user with her email'));
331: }
332:
333: $tnu = LoginTableName::$TABLE_NAME_USERS;
334: $tnd = LoginTableName::$TABLE_NAME_DATAS;
335:
336: $query = SqlQuery::getTemp(SqlQuery::$TYPE_SELECT);
337: $query->initSelect('email, role', $tnu);
338: if ($dataKey !== null && $dataValue !== null) {
339: $query->setFrom('`' . $tnu . '` '
340: . 'LEFT JOIN ' . $tnd . ' '
341: . 'ON ' . $tnu . '.email = ' . $tnd . '.user_email');
342: $query->setWhere($tnd . '.key = \'' . $dataKey . '\' AND ' . $tnd . '.value = \'' . $dataValue . '\'');
343: }
344:
345: foreach ($this->_db->fetchAll($query) as $user) {
346: $list[$user['email']] = new LoginUser($this->_db);
347: $list[$user['email']]->init($user['email'], 'null', $user['role']);
348: }
349:
350: return new ValueObject($list);
351: }
352:
353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393:
394: public function addUser($email, $realPass, $role = 1) {
395: $userConnectedVO = $this->getUserConnected();
396: if ($userConnectedVO->error) {
397: return new ValueObject(false, true, $userConnectedVO->errorList);
398: } else if ($userConnectedVO->content->getRole() != LoginUser::$ROLE_ADMIN) {
399: return new ValueObject(false, true, array('Only admin can add a user.'));
400: }
401:
402: return registerUser($email, $realPass, $role);
403: }
404:
405: 406: 407: 408: 409: 410: 411: 412:
413: public function registerUser($email, $realPass, $role = 1) {
414: $sameEmail = $this->getUserByEMail($email);
415: if (!$sameEmail->error && $sameEmail->content !== null) {
416: return new ValueObject(false, true, array('An user with the same email already exist.'));
417: }
418:
419: $query = SqlQuery::getTemp(SqlQuery::$TYPE_INSERT);
420: $values = array();
421: $values['email'] = $email;
422: $values['pass'] = $this->passEncrypt($realPass, $email);
423: $values['role'] = $role;
424: $values['token'] = $this->generateToken();
425: $insert = LoginTableName::$TABLE_NAME_USERS;
426: $query->initInsertValues($insert, $values);
427: $this->_db->execute($query);
428:
429: return new ValueObject(true);
430: }
431:
432: 433: 434: 435: 436: 437: 438: 439: 440:
441: public function addDataToUser($userEmail, $dataKey, $dataValue) {
442: $userConnectedVO = $this->getUserConnected();
443: if ($userConnectedVO->error) {
444: return new ValueObject(false, true, $userConnectedVO->errorList);
445: } else if ($userConnectedVO->content->getRole() != LoginUser::$ROLE_ADMIN ||
446: $userConnectedVO->content->getEmail() == $userEmail) {
447: return new ValueObject(false, true, array('Only admin or the user can add data.'));
448: }
449:
450: if ($this->_db->exist(LoginTableName::$TABLE_NAME_DATAS)) {
451: $query = SqlQuery::getTemp(SqlQuery::$TYPE_INSERT);
452: $values = array();
453: $values['user_email'] = $userEmail;
454: $values['key'] = $dataKey;
455: $values['value'] = $dataValue;
456: $insert = LoginTableName::$TABLE_NAME_DATAS;
457: $query->initInsertValues($insert, $values);
458:
459: $added = $this->_db->execute($query);
460: if ($added) {
461: return new ValueObject(true);
462: } else {
463: return new ValueObject(false, true, array('An error as occured in the data base.'));
464: }
465: }
466:
467: return new ValueObject(false, true, array('This table does not exist in the database'));
468: }
469:
470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507:
508: public function connect($email, $realPass) {
509: $time = time();
510:
511:
512: $query = SqlQuery::getTemp(SqlQuery::$TYPE_INSERT);
513: $datas = array();
514:
515: $datas['user_email'] = $email;
516: $datas['time'] = $time;
517: $datas['ip'] = $_SERVER["REMOTE_ADDR"];
518: $query->initInsertValues(LoginTableName::$TABLE_NAME_LOGS, $datas);
519: $this->_db->execute($query);
520:
521: $query2 = SqlQuery::getTemp();
522: $query2->initCount(LoginTableName::$TABLE_NAME_LOGS, array('user_email' => $email, 'time' => ($time - 2)), array('=', '>'));
523: if ($this->_db->count($query2) > 1) {
524: return new ValueObject(false, true, array('The server has detected an attack by brute forcing.'));
525: }
526:
527:
528: $cryptedPass = $this->passEncrypt($realPass, $email);
529: $where3 = array('email' => $email, 'pass' => $cryptedPass);
530: $query3 = SqlQuery::getTemp();
531: $query3->initSelect('*', LoginTableName::$TABLE_NAME_USERS, $where3);
532: $rows = $this->_db->fetchAll($query3);
533: if (count($rows) < 1) {
534: return new ValueObject(false, true, array('No password matches this email.'));
535: }
536:
537: $token = $this->generateToken();
538: $query4 = SqlQuery::getTemp(SqlQuery::$TYPE_UPDATE);
539: $query4->setUpdate(LoginTableName::$TABLE_NAME_USERS);
540: $query4->setSet('token = \'' . $token . '\'');
541: $query4->setWhere('email = \'' . $rows[0]['email'] . '\'');
542:
543: if ($this->_db->execute($query4)) {
544: $_SESSION['login_token'] = $token;
545: return new ValueObject(true);
546: } else {
547: return new ValueObject(false, true, array('An error in the data base has occurred.'));
548: }
549: }
550:
551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571:
572: public function disconnect() {
573: $vo = $this->getUserConnected();
574: if (!$vo->error) {
575: $user = $vo->content;
576:
577: $token = $this->generateToken();
578: $query = SqlQuery::getTemp(SqlQuery::$TYPE_UPDATE);
579: $query->setUpdate(LoginTableName::$TABLE_NAME_USERS);
580: $query->setSet('token = \'' . $token . '\'');
581: $query->setWhere('email = \'' . $user->getEmail() . '\'');
582: $this->_db->execute($query);
583: }
584:
585: $this->_user = null;
586:
587: session_unset();
588: session_destroy();
589: return true;
590: }
591:
592: private function generateToken() {
593: return md5(rand(0, 9999) . microtime());
594: }
595:
596: 597: 598:
599: private function create() {
600: $req1 = SqlQuery::getTemp(SqlQuery::$TYPE_CREATE);
601: $create1 = 'TABLE IF NOT EXISTS `' . LoginTableName::$TABLE_NAME_USERS . '` ( '
602: . 'email TEXT UNIQUE, '
603: . 'pass TEXT, '
604: . 'role INT DEFAULT 0, '
605: . 'token TEXT DEFAULT \'' . $this->generateToken() . '\' '
606: . ');';
607: $req1->setCreate($create1);
608: $this->_db->execute($req1);
609:
610: $req2 = SqlQuery::getTemp(SqlQuery::$TYPE_CREATE);
611: $create2 = 'TABLE IF NOT EXISTS `' . LoginTableName::$TABLE_NAME_LOGS . '` ( '
612: . 'user_email TEXT, '
613: . 'time INT, '
614: . 'ip TEXT );';
615: $req2->setCreate($create2);
616: $this->_db->execute($req2);
617:
618: $req3 = SqlQuery::getTemp(SqlQuery::$TYPE_CREATE);
619: $create3 = 'TABLE IF NOT EXISTS `' . LoginTableName::$TABLE_NAME_DATAS . '` ( '
620: . 'user_email TEXT, '
621: . 'key INT, '
622: . 'value TEXT );';
623: $req3->setCreate($create3);
624: $this->_db->execute($req3);
625: }
626:
627: 628: 629: 630: 631:
632: private function isDbInitialized() {
633: return $this->_db->exist(LoginTableName::$TABLE_NAME_USERS);
634: }
635:
636: private function __construct($dbDsn) {
637: if (!self::$_IS_SESSION_STARTED) {
638: session_start();
639: self::$_IS_SESSION_STARTED = true;
640: }
641:
642: $this->_db = DataBase::getInstance($dbDsn);
643:
644: if (!$this->isDbInitialized()) {
645: $this->create();
646: }
647: }
648:
649: 650: 651: 652: 653: 654:
655: public static function getInstance($dbDsn) {
656: if (!isset(self::$_INSTANCE[$dbDsn])) {
657: self::$_INSTANCE[$dbDsn] = new Login($dbDsn);
658: }
659: return self::$_INSTANCE[$dbDsn];
660: }
661:
662: final private function __clone() {
663: if (_DEBUG) {
664: Debug::getInstance()->addError('You can\'t clone a multiton');
665: }
666: }
667:
668: }
669: