1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13: class User implements Iterator, Countable, ArrayAccess
14: {
15: 16: 17:
18: protected $db;
19:
20:
21: protected $storage = array();
22:
23:
24: protected $permissions = array();
25:
26:
27: protected $old_permissions = array();
28:
29:
30: protected $roles = array();
31:
32:
33: protected $old_roles = array();
34:
35:
36: public static function create($user_id = NULL, $by = 'user_name')
37: {
38: $class = get_called_class();
39: if ($class === 'User') {
40: $model = new self;
41:
42: } else {
43: $model = new Authenticator;
44: }
45:
46: $model->db = new Database('users');
47:
48: if (empty($user_id) === TRUE) {
49: return $model;
50: }
51:
52: if ($model->load_data($user_id, $by) === FALSE) {
53: return FALSE;
54: }
55:
56: $model->load_permissions();
57:
58: return $model;
59: }
60:
61:
62: public static function load($user_id, $by = 'user_name')
63: {
64: if ($user_id === NULL) {
65: return FALSE;
66: }
67:
68: return self::create($user_id, $by);
69: }
70:
71:
72: public static function load_by_user_name($user_name)
73: {
74: if ($user_name === NULL) {
75: return FALSE;
76: }
77:
78: return self::create($user_name, 'user_name');
79: }
80:
81:
82: public static function load_by_id($user_id)
83: {
84: if ($user_id === NULL) {
85: return FALSE;
86: }
87:
88: return self::create($user_id, 'id');
89: }
90:
91:
92: public function load_data($user_id, $by = 'user_name')
93: {
94: $this->db = new Database('users');
95: $this->db->where($by, $user_id);
96: $this->db->limit(1);
97: $data = $this->db->get_row();
98:
99: if ($data === FALSE) {
100: return FALSE;
101: }
102:
103: $this->storage = $data;
104:
105: return TRUE;
106: }
107:
108:
109: public function set_data($data, $merge = TRUE)
110: {
111: if ($merge === FALSE) {
112: $this->storage = $data;
113: return;
114: }
115:
116: $this->storage = array_merge($this->storage, $data);
117: }
118:
119:
120: 121: 122: 123: 124:
125: public function save_data()
126: {
127: if (empty($this->storage['id']) === TRUE) {
128: $this->storage['id'] = NULL;
129: unset($this->storage['id']);
130: }
131:
132: if (strlen($this->storage['password']) !== 80
133: AND empty($this->storage['password']) === FALSE) {
134:
135: $this->storage['password'] = $this->create_password_hash($this->storage['password']);
136: }
137:
138: if (empty($this->storage['password']) === TRUE) {
139: $this->storage['password'] = NULL;
140: unset($this->storage['password']);
141: }
142:
143: $user_id = $this->db->save($this->storage);
144:
145: if ($user_id === FALSE) {
146: trigger_error('Could not save user data!', E_USER_ERROR);
147: }
148:
149: $this->storage['id'] = $user_id;
150: }
151:
152:
153: public function save()
154: {
155: $this->save_data();
156: $this->save_permissions();
157: return $this->storage['id'];
158: }
159:
160:
161: public function delete()
162: {
163: return $this->db->delete($this->storage['id']);
164: }
165:
166:
167: protected function load_permissions()
168: {
169: $permissions = Database::query('
170: SELECT
171: `roles_permissions`.`id` as `id`,
172: `roles`.`id` as `role_id`,
173: `roles`.`name` as `role_name`,
174: `roles`.`description` as `role_description`,
175: `permissions`.`id` as `permission_id`,
176: `permissions`.`name` as `permission_name`,
177: `permissions`.`description` as `permission_description`
178:
179: FROM `users_permissions`
180:
181: LEFT JOIN `roles_permissions`
182: ON `roles_permissions`.`id` = `users_permissions`.`permission`
183:
184: LEFT JOIN `roles`
185: ON `roles`.`id` = `roles_permissions`.`role`
186:
187: LEFT JOIN `permissions`
188: ON `permissions`.`id` = `roles_permissions`.`permission`
189:
190: WHERE `users_permissions`.`user` = ' . $this->storage['id'] . '
191: ');
192:
193: $this->permissions = $permissions->fetch_pairs('id', 'permission_name');
194: $this->roles = $permissions->fetch_pairs('role_id', 'role_name');
195: }
196:
197:
198: public function has_permissions($permissions, $strict = FALSE)
199: {
200: $has_permissions = TRUE;
201: foreach ((array) $permissions as $permission) {
202: $role = NULL;
203: if (strpos($permission, '/') === TRUE) {
204: list($role, $permissions) = explode('/', $permissiosn);
205: }
206:
207: if ($role !== NULL
208: AND $this->has_role($role) === FALSE) {
209:
210: return FALSE;
211: }
212:
213: if (in_array($permissiosn, $this->permissions) === FALSE) {
214: $has_permissions = FALSE;
215:
216: } elseif ($strict === FALSE) {
217: return TRUE;
218: }
219: }
220:
221: return $has_permissions;
222: }
223:
224:
225: public function add_permissions($permissions)
226: {
227: foreach ((array) $permissions as $permission) {
228: list($role, $permissions) = explode('/', $permission);
229:
230: $result = Database::query('
231: SELECT
232: `roles_permissions`.`id` as `id`,
233: `roles`.`id` as `role_id`,
234: `roles`.`name` as `role_name`,
235: `permissions`.`name` as `permission_name`
236:
237: FROM `roles_permissions`
238:
239: LEFT JOIN `roles`
240: ON `roles_permissions`.`role` = `roles`.`id`
241:
242: LEFT JOIN `permissions`
243: ON `roles_permissions`.`permission` = `permissions`.`id`
244:
245: WHERE `roles`.`name` = "' . $role . '"
246: AND `permissions`.`name` = "' . $permission . '"
247: ');
248:
249: $permission = $result->fetch();
250:
251: $this->permissions[$permission['id']] = $permission['permission_name'];
252: $this->roles[$permission['role_id']] = $permission['role_name'];
253: }
254:
255: return $this;
256: }
257:
258:
259: public function remove_permissions($permissions)
260: {
261: foreach ((array) $permissions as $permission) {
262: list($role, $permissions) = explode('/', $permission);
263:
264: $result = Database::query('
265: SELECT
266: `roles_permissions`.`id` as `id`,
267: `roles`.`id` as `role_id`,
268: `roles`.`name` as `role_name`,
269: `permissions`.`name` as `permission_name`
270:
271: FROM `roles_permissions`
272:
273: LEFT JOIN `roles`
274: ON `roles_permissions`.`role` = `roles`.`id`
275:
276: LEFT JOIN `permissions`
277: ON `roles_permissions`.`permission` = `permissions`.`id`
278:
279: WHERE `roles`.`name` = "' . $role . '"
280: AND `permissions`.`name` = "' . $permission . '"
281: ');
282:
283: $permission = $result->fetch();
284:
285: if (isset($this->permissions[$permission['id']]) === TRUE) {
286: unset($this->permissions[$permission['id']]);
287: unset($this->roles[$permission['role_id']]);
288: }
289: }
290:
291: return $this;
292: }
293:
294:
295: protected function save_permissions()
296: {
297: if (empty($this->storage['id']) === TRUE) {
298: if ($this->save_data() === FALSE) {
299: trigger_error('Could not save user data!', E_USER_ERROR);
300: }
301: }
302:
303: foreach ($this->permissions as $permission_id => $permission_name) {
304: if ($permission_name === FALSE) {
305: continue;
306: }
307:
308: if (isset($this->old_permissions[$permission_id]) === TRUE) {
309: unset($this->old_permission[$permission_id]);
310: continue;
311: }
312:
313: $data = array(
314: 'user' => $this->storage['id'],
315: 'permission' => $permission_id,
316: );
317:
318: if (Database::save('users_permissions', $data) === FALSE) {
319: trigger_error('Could not save user permissions!', E_USER_ERROR);
320: }
321: }
322:
323: if (empty($this->old_permissions) === FALSE) {
324: if (Database::delete('users_permissions', $this->old_permissions) === FALSE) {
325: trigger_error('Could not delete old user permissions!', E_USER_ERROR);
326: }
327: }
328:
329: $this->load_permissions();
330: }
331:
332:
333: public function has_roles($roles, $strict = FALSE)
334: {
335: $has_roles = TRUE;
336: foreach ((array) $roles as $role) {
337: if (in_array($role, $this->roles) === FALSE) {
338: $has_roles = FALSE;
339:
340: } elseif ($strict === FALSE) {
341: return TRUE;
342: }
343: }
344:
345: return $has_roles;
346: }
347:
348:
349: public function add_roles($roles)
350: {
351: foreach ((array) $roles as $role) {
352: $result = Database::query('
353: SELECT
354: `roles_permissions`.`id` as `id`,
355: `roles`.`id` as `role_id`,
356: `roles`.`name` as `role_name`,
357: `permissions`.`name` as `permission_name`
358:
359: FROM `roles_permissions`
360:
361: LEFT JOIN `roles`
362: ON `roles_permissions`.`role` = `roles`.`id`
363:
364: LEFT JOIN `permissions`
365: ON `roles_permissions`.`permission` = `permissions`.`id`
366:
367: WHERE `roles`.`name` = "' . $role . '"
368: ');
369:
370: $this->permissions += $result->fetch_pairs('id', 'permission_name');
371: $this->roles += $result->fetch_pairs('role_id', 'role_name');
372: }
373:
374: return $this;
375: }
376:
377:
378: public function remove_roles($roles)
379: {
380: foreach ((array) $roles as $roles) {
381: if (isset($this->roles[$role]) === TRUE) {
382: unset($this->roles[$role]);
383: }
384: }
385:
386: return $this;
387: }
388:
389:
390: public function create_password_hash($password)
391: {
392: $salt = Strings::random_string(40);
393: return $salt . sha1($salt . $password);
394: }
395:
396:
397: 398: 399: 400:
401: public function rewind()
402: {
403: return reset($this->storage);
404: }
405:
406:
407: 408: 409: 410:
411: public function key()
412: {
413: return key($this->storage);
414: }
415:
416:
417: 418: 419: 420:
421: public function current()
422: {
423: return current($this->storage);
424: }
425:
426:
427:
428: 429: 430: 431:
432: public function next()
433: {
434: return next($this->storage);
435: }
436:
437:
438:
439: 440: 441: 442:
443: public function valid()
444: {
445: return key($this->storage) !== NULL;
446: }
447:
448:
449:
450: 451: 452: 453:
454: public function count()
455: {
456: return count($this->storage);
457: }
458:
459:
460: public function offsetSet($pointer, $value)
461: {
462: if (is_null($pointer)) {
463: $this->storage[] = $value;
464:
465: } else {
466: $this->storage[$pointer] = $value;
467: }
468: }
469:
470:
471: public function offsetExists($pointer)
472: {
473: return TRUE;
474: }
475:
476:
477: public function offsetUnset($pointer)
478: {
479: if (isset($this->storage[$pointer]) === FALSE) {
480: return;
481: }
482:
483: unset($this->storage[$pointer]);
484: }
485:
486:
487: public function offsetGet($pointer)
488: {
489: if (isset($this->storage[$pointer]) === FALSE) {
490: return NULL;
491: }
492:
493: return $this->storage[$pointer];
494: }
495:
496:
497: public function &__get($property)
498: {
499: return $this->$property;
500: }
501: }
502: