Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
permission.php
001 <?php
002 /**
003 *
004 * This file is part of the phpBB Forum Software package.
005 *
006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
007 * @license GNU General Public License, version 2 (GPL-2.0)
008 *
009 * For full copyright and license information, please see
010 * the docs/CREDITS.txt file.
011 *
012 */
013
014 namespace phpbb\db\migration\tool;
015
016 /**
017 * Migration permission management tool
018 */
019 class permission implements \phpbb\db\migration\tool\tool_interface
020 {
021 /** @var \phpbb\auth\auth */
022 protected $auth;
023
024 /** @var \includes\acp\auth\auth_admin */
025 protected $auth_admin;
026
027 /** @var \phpbb\cache\service */
028 protected $cache;
029
030 /** @var \phpbb\db\driver\driver_interface */
031 protected $db;
032
033 /** @var string */
034 protected $phpbb_root_path;
035
036 /** @var string */
037 protected $php_ext;
038
039 /**
040 * Constructor
041 *
042 * @param \phpbb\db\driver\driver_interface $db
043 * @param \phpbb\cache\service $cache
044 * @param \phpbb\auth\auth $auth
045 * @param string $phpbb_root_path
046 * @param string $php_ext
047 */
048 public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\auth\auth $auth, $phpbb_root_path, $php_ext)
049 {
050 $this->db = $db;
051 $this->cache = $cache;
052 $this->auth = $auth;
053 $this->phpbb_root_path = $phpbb_root_path;
054 $this->php_ext = $php_ext;
055
056 if (!class_exists('auth_admin'))
057 {
058 include($this->phpbb_root_path . 'includes/acp/auth.' . $this->php_ext);
059 }
060 $this->auth_admin = new \auth_admin();
061 }
062
063 /**
064 * {@inheritdoc}
065 */
066 public function get_name()
067 {
068 return 'permission';
069 }
070
071 /**
072 * Permission Exists
073 *
074 * Check if a permission (auth) setting exists
075 *
076 * @param string $auth_option The name of the permission (auth) option
077 * @param bool $global True for checking a global permission setting,
078 * False for a local permission setting
079 * @return bool true if it exists, false if not
080 */
081 public function exists($auth_option, $global = true)
082 {
083 if ($global)
084 {
085 $type_sql = ' AND is_global = 1';
086 }
087 else
088 {
089 $type_sql = ' AND is_local = 1';
090 }
091
092 $sql = 'SELECT auth_option_id
093 FROM ' . ACL_OPTIONS_TABLE . "
094 WHERE auth_option = '" . $this->db->sql_escape($auth_option) . "'"
095 . $type_sql;
096 $result = $this->db->sql_query($sql);
097
098 $row = $this->db->sql_fetchrow($result);
099 $this->db->sql_freeresult($result);
100
101 if ($row)
102 {
103 return true;
104 }
105
106 return false;
107 }
108
109 /**
110 * Permission Add
111 *
112 * Add a permission (auth) option
113 *
114 * @param string $auth_option The name of the permission (auth) option
115 * @param bool $global True for checking a global permission setting,
116 * False for a local permission setting
117 * @param int|false $copy_from If set, contains the id of the permission from which to copy the new one.
118 * @return null
119 */
120 public function add($auth_option, $global = true, $copy_from = false)
121 {
122 if ($this->exists($auth_option, $global))
123 {
124 return;
125 }
126
127 // We've added permissions, so set to true to notify the user.
128 $this->permissions_added = true;
129
130 // We have to add a check to see if the !$global (if global, local, and if local, global) permission already exists. If it does, acl_add_option currently has a bug which would break the ACL system, so we are having a work-around here.
131 if ($this->exists($auth_option, !$global))
132 {
133 $sql_ary = array(
134 'is_global' => 1,
135 'is_local' => 1,
136 );
137 $sql = 'UPDATE ' . ACL_OPTIONS_TABLE . '
138 SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . "
139 WHERE auth_option = '" . $this->db->sql_escape($auth_option) . "'";
140 $this->db->sql_query($sql);
141 }
142 else
143 {
144 if ($global)
145 {
146 $this->auth_admin->acl_add_option(array('global' => array($auth_option)));
147 }
148 else
149 {
150 $this->auth_admin->acl_add_option(array('local' => array($auth_option)));
151 }
152 }
153
154 // The permission has been added, now we can copy it if needed
155 if ($copy_from && isset($this->auth_admin->acl_options['id'][$copy_from]))
156 {
157 $old_id = $this->auth_admin->acl_options['id'][$copy_from];
158 $new_id = $this->auth_admin->acl_options['id'][$auth_option];
159
160 $tables = array(ACL_GROUPS_TABLE, ACL_ROLES_DATA_TABLE, ACL_USERS_TABLE);
161
162 foreach ($tables as $table)
163 {
164 $sql = 'SELECT *
165 FROM ' . $table . '
166 WHERE auth_option_id = ' . $old_id;
167 $result = $this->db->sql_query($sql);
168
169 $sql_ary = array();
170 while ($row = $this->db->sql_fetchrow($result))
171 {
172 $row['auth_option_id'] = $new_id;
173 $sql_ary[] = $row;
174 }
175 $this->db->sql_freeresult($result);
176
177 if (!empty($sql_ary))
178 {
179 $this->db->sql_multi_insert($table, $sql_ary);
180 }
181 }
182
183 $this->auth_admin->acl_clear_prefetch();
184 }
185 }
186
187 /**
188 * Permission Remove
189 *
190 * Remove a permission (auth) option
191 *
192 * @param string $auth_option The name of the permission (auth) option
193 * @param bool $global True for checking a global permission setting,
194 * False for a local permission setting
195 * @return null
196 */
197 public function remove($auth_option, $global = true)
198 {
199 if (!$this->exists($auth_option, $global))
200 {
201 return;
202 }
203
204 if ($global)
205 {
206 $type_sql = ' AND is_global = 1';
207 }
208 else
209 {
210 $type_sql = ' AND is_local = 1';
211 }
212 $sql = 'SELECT auth_option_id, is_global, is_local
213 FROM ' . ACL_OPTIONS_TABLE . "
214 WHERE auth_option = '" . $this->db->sql_escape($auth_option) . "'" .
215 $type_sql;
216 $result = $this->db->sql_query($sql);
217 $row = $this->db->sql_fetchrow($result);
218 $this->db->sql_freeresult($result);
219
220 $id = (int) $row['auth_option_id'];
221
222 // If it is a local and global permission, do not remove the row! :P
223 if ($row['is_global'] && $row['is_local'])
224 {
225 $sql = 'UPDATE ' . ACL_OPTIONS_TABLE . '
226 SET ' . (($global) ? 'is_global = 0' : 'is_local = 0') . '
227 WHERE auth_option_id = ' . $id;
228 $this->db->sql_query($sql);
229 }
230 else
231 {
232 // Delete time
233 $tables = array(ACL_GROUPS_TABLE, ACL_ROLES_DATA_TABLE, ACL_USERS_TABLE, ACL_OPTIONS_TABLE);
234 foreach ($tables as $table)
235 {
236 $this->db->sql_query('DELETE FROM ' . $table . '
237 WHERE auth_option_id = ' . $id);
238 }
239 }
240
241 // Purge the auth cache
242 $this->cache->destroy('_acl_options');
243 $this->auth->acl_clear_prefetch();
244 }
245
246 /**
247 * Check if a permission role exists
248 *
249 * @param string $role_name The role name
250 *
251 * @return int The id of the role if it exists, 0 otherwise
252 */
253 public function role_exists($role_name)
254 {
255 $sql = 'SELECT role_id
256 FROM ' . ACL_ROLES_TABLE . "
257 WHERE role_name = '" . $this->db->sql_escape($role_name) . "'";
258 $result = $this->db->sql_query($sql);
259 $role_id = (int) $this->db->sql_fetchfield('role_id');
260 $this->db->sql_freeresult($result);
261
262 return $role_id;
263 }
264
265 /**
266 * Add a new permission role
267 *
268 * @param string $role_name The new role name
269 * @param string $role_type The type (u_, m_, a_)
270 * @param string $role_description Description of the new role
271 *
272 * @return null
273 */
274 public function role_add($role_name, $role_type, $role_description = '')
275 {
276 if ($this->role_exists($role_name))
277 {
278 return;
279 }
280
281 $sql = 'SELECT MAX(role_order) AS max_role_order
282 FROM ' . ACL_ROLES_TABLE . "
283 WHERE role_type = '" . $this->db->sql_escape($role_type) . "'";
284 $this->db->sql_query($sql);
285 $role_order = (int) $this->db->sql_fetchfield('max_role_order');
286 $role_order = (!$role_order) ? 1 : $role_order + 1;
287
288 $sql_ary = array(
289 'role_name' => $role_name,
290 'role_description' => $role_description,
291 'role_type' => $role_type,
292 'role_order' => $role_order,
293 );
294
295 $sql = 'INSERT INTO ' . ACL_ROLES_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary);
296 $this->db->sql_query($sql);
297
298 return $this->db->sql_nextid();
299 }
300
301 /**
302 * Update the name on a permission role
303 *
304 * @param string $old_role_name The old role name
305 * @param string $new_role_name The new role name
306 * @return null
307 * @throws \phpbb\db\migration\exception
308 */
309 public function role_update($old_role_name, $new_role_name)
310 {
311 if (!$this->role_exists($old_role_name))
312 {
313 throw new \phpbb\db\migration\exception('ROLE_NOT_EXIST', $old_role_name);
314 }
315
316 $sql = 'UPDATE ' . ACL_ROLES_TABLE . "
317 SET role_name = '" . $this->db->sql_escape($new_role_name) . "'
318 WHERE role_name = '" . $this->db->sql_escape($old_role_name) . "'";
319 $this->db->sql_query($sql);
320 }
321
322 /**
323 * Remove a permission role
324 *
325 * @param string $role_name The role name to remove
326 * @return null
327 */
328 public function role_remove($role_name)
329 {
330 if (!($role_id = $this->role_exists($role_name)))
331 {
332 return;
333 }
334
335 // Get the role type
336 $sql = 'SELECT role_type
337 FROM ' . ACL_ROLES_TABLE . '
338 WHERE role_id = ' . (int) $role_id;
339 $result = $this->db->sql_query($sql);
340 $role_type = $this->db->sql_fetchfield('role_type');
341 $this->db->sql_freeresult($result);
342
343 // Get complete auth array
344 $sql = 'SELECT auth_option, auth_option_id
345 FROM ' . ACL_OPTIONS_TABLE . "
346 WHERE auth_option " . $this->db->sql_like_expression($role_type . $this->db->get_any_char());
347 $result = $this->db->sql_query($sql);
348
349 $auth_settings = [];
350 while ($row = $this->db->sql_fetchrow($result))
351 {
352 $auth_settings[$row['auth_option']] = ACL_NO;
353 }
354 $this->db->sql_freeresult($result);
355
356 // Get the role auth settings we need to re-set...
357 $sql = 'SELECT o.auth_option, r.auth_setting
358 FROM ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' o
359 WHERE o.auth_option_id = r.auth_option_id
360 AND r.role_id = ' . (int) $role_id;
361 $result = $this->db->sql_query($sql);
362
363 while ($row = $this->db->sql_fetchrow($result))
364 {
365 $auth_settings[$row['auth_option']] = $row['auth_setting'];
366 }
367 $this->db->sql_freeresult($result);
368
369 // Get role assignments
370 $hold_ary = $this->auth_admin->get_role_mask($role_id);
371
372 // Re-assign permissions
373 foreach ($hold_ary as $forum_id => $forum_ary)
374 {
375 if (isset($forum_ary['users']))
376 {
377 $this->auth_admin->acl_set('user', $forum_id, $forum_ary['users'], $auth_settings, 0, false);
378 }
379
380 if (isset($forum_ary['groups']))
381 {
382 $this->auth_admin->acl_set('group', $forum_id, $forum_ary['groups'], $auth_settings, 0, false);
383 }
384 }
385
386 // Remove role from users and groups just to be sure (happens through acl_set)
387 $sql = 'DELETE FROM ' . ACL_USERS_TABLE . '
388 WHERE auth_role_id = ' . $role_id;
389 $this->db->sql_query($sql);
390
391 $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . '
392 WHERE auth_role_id = ' . $role_id;
393 $this->db->sql_query($sql);
394
395 $sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . '
396 WHERE role_id = ' . $role_id;
397 $this->db->sql_query($sql);
398
399 $sql = 'DELETE FROM ' . ACL_ROLES_TABLE . '
400 WHERE role_id = ' . $role_id;
401 $this->db->sql_query($sql);
402
403 $this->auth->acl_clear_prefetch();
404 }
405
406 /**
407 * Permission Set
408 *
409 * Allows you to set permissions for a certain group/role
410 *
411 * @param string $name The name of the role/group
412 * @param string|array $auth_option The auth_option or array of
413 * auth_options you would like to set
414 * @param string $type The type (role|group)
415 * @param bool $has_permission True if you want to give them permission,
416 * false if you want to deny them permission
417 * @return null
418 * @throws \phpbb\db\migration\exception
419 */
420 public function permission_set($name, $auth_option, $type = 'role', $has_permission = true)
421 {
422 if (!is_array($auth_option))
423 {
424 $auth_option = array($auth_option);
425 }
426
427 $new_auth = array();
428 $sql = 'SELECT auth_option_id
429 FROM ' . ACL_OPTIONS_TABLE . '
430 WHERE ' . $this->db->sql_in_set('auth_option', $auth_option);
431 $result = $this->db->sql_query($sql);
432 while ($row = $this->db->sql_fetchrow($result))
433 {
434 $new_auth[] = (int) $row['auth_option_id'];
435 }
436 $this->db->sql_freeresult($result);
437
438 $type = (string) $type; // Prevent PHP bug.
439 if (empty($new_auth) || !in_array($type, ['role','group']))
440 {
441 return;
442 }
443
444 $current_auth = array();
445
446 switch ($type)
447 {
448 case 'role':
449 if (!($role_id = $this->role_exists($name)))
450 {
451 throw new \phpbb\db\migration\exception('ROLE_NOT_EXIST', $name);
452 }
453
454 $sql = 'SELECT auth_option_id, auth_setting
455 FROM ' . ACL_ROLES_DATA_TABLE . '
456 WHERE role_id = ' . $role_id;
457 $result = $this->db->sql_query($sql);
458 while ($row = $this->db->sql_fetchrow($result))
459 {
460 $current_auth[$row['auth_option_id']] = $row['auth_setting'];
461 }
462 $this->db->sql_freeresult($result);
463 break;
464
465 case 'group':
466 $sql = 'SELECT group_id
467 FROM ' . GROUPS_TABLE . "
468 WHERE group_name = '" . $this->db->sql_escape($name) . "'";
469 $this->db->sql_query($sql);
470 $group_id = (int) $this->db->sql_fetchfield('group_id');
471
472 if (!$group_id)
473 {
474 throw new \phpbb\db\migration\exception('GROUP_NOT_EXIST', $name);
475 }
476
477 // If the group has a role set for them we will add the requested permissions to that role.
478 $sql = 'SELECT auth_role_id
479 FROM ' . ACL_GROUPS_TABLE . '
480 WHERE group_id = ' . $group_id . '
481 AND auth_role_id <> 0
482 AND forum_id = 0';
483 $this->db->sql_query($sql);
484 $role_id = (int) $this->db->sql_fetchfield('auth_role_id');
485 if ($role_id)
486 {
487 $sql = 'SELECT role_name, role_type
488 FROM ' . ACL_ROLES_TABLE . '
489 WHERE role_id = ' . $role_id;
490 $this->db->sql_query($sql);
491 $role_data = $this->db->sql_fetchrow();
492 if (!$role_data)
493 {
494 throw new \phpbb\db\migration\exception('ROLE_ASSIGNED_NOT_EXIST', $name, $role_id);
495 }
496
497 $role_name = $role_data['role_name'];
498 $role_type = $role_data['role_type'];
499
500 // Filter new auth options to match the role type: a_ | f_ | m_ | u_
501 // Set new auth options to the role only if options matching the role type were found
502 $auth_option = array_filter($auth_option,
503 function ($option) use ($role_type)
504 {
505 return strpos($option, $role_type) === 0;
506 }
507 );
508
509 if (count($auth_option))
510 {
511 return $this->permission_set($role_name, $auth_option, 'role', $has_permission);
512 }
513 }
514
515 $sql = 'SELECT auth_option_id, auth_setting
516 FROM ' . ACL_GROUPS_TABLE . '
517 WHERE group_id = ' . $group_id;
518 $result = $this->db->sql_query($sql);
519 while ($row = $this->db->sql_fetchrow($result))
520 {
521 $current_auth[$row['auth_option_id']] = $row['auth_setting'];
522 }
523 $this->db->sql_freeresult($result);
524 break;
525 }
526
527 $sql_ary = $auth_update_list = [];
528 $table = $type == 'role' ? ACL_ROLES_DATA_TABLE : ACL_GROUPS_TABLE;
529 foreach ($new_auth as $auth_option_id)
530 {
531 if (!isset($current_auth[$auth_option_id]))
532 {
533 $sql_ary[] = [
534 $type . '_id' => ${$type . '_id'},
535 'auth_option_id' => $auth_option_id,
536 'auth_setting' => (int) $has_permission,
537 ];
538 }
539 else
540 {
541 $auth_update_list[] = $auth_option_id;
542 }
543 }
544 $this->db->sql_multi_insert($table, $sql_ary);
545
546 if (count($auth_update_list))
547 {
548 $sql = 'UPDATE ' . $table . '
549 SET auth_setting = ' . (int) $has_permission . '
550 WHERE ' . $this->db->sql_in_set('auth_option_id', $auth_update_list) . '
551 AND ' . $type . '_id = ' . (int) ${$type . '_id'};
552 $this->db->sql_query($sql);
553 }
554
555 $this->auth->acl_clear_prefetch();
556 }
557
558 /**
559 * Permission Unset
560 *
561 * Allows you to unset (remove) permissions for a certain group/role
562 *
563 * @param string $name The name of the role/group
564 * @param string|array $auth_option The auth_option or array of
565 * auth_options you would like to set
566 * @param string $type The type (role|group)
567 * @return null
568 * @throws \phpbb\db\migration\exception
569 */
570 public function permission_unset($name, $auth_option, $type = 'role')
571 {
572 if (!is_array($auth_option))
573 {
574 $auth_option = array($auth_option);
575 }
576
577 $to_remove = array();
578 $sql = 'SELECT auth_option_id
579 FROM ' . ACL_OPTIONS_TABLE . '
580 WHERE ' . $this->db->sql_in_set('auth_option', $auth_option);
581 $result = $this->db->sql_query($sql);
582 while ($row = $this->db->sql_fetchrow($result))
583 {
584 $to_remove[] = (int) $row['auth_option_id'];
585 }
586 $this->db->sql_freeresult($result);
587
588 if (empty($to_remove))
589 {
590 return;
591 }
592
593 $type = (string) $type; // Prevent PHP bug.
594
595 switch ($type)
596 {
597 case 'role':
598 if (!($role_id = $this->role_exists($name)))
599 {
600 throw new \phpbb\db\migration\exception('ROLE_NOT_EXIST', $name);
601 }
602
603 $sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . '
604 WHERE ' . $this->db->sql_in_set('auth_option_id', $to_remove) . '
605 AND role_id = ' . (int) $role_id;
606 $this->db->sql_query($sql);
607 break;
608
609 case 'group':
610 $sql = 'SELECT group_id
611 FROM ' . GROUPS_TABLE . "
612 WHERE group_name = '" . $this->db->sql_escape($name) . "'";
613 $this->db->sql_query($sql);
614 $group_id = (int) $this->db->sql_fetchfield('group_id');
615
616 if (!$group_id)
617 {
618 throw new \phpbb\db\migration\exception('GROUP_NOT_EXIST', $name);
619 }
620
621 // If the group has a role set for them we will remove the requested permissions from that role.
622 $sql = 'SELECT auth_role_id
623 FROM ' . ACL_GROUPS_TABLE . '
624 WHERE group_id = ' . $group_id . '
625 AND auth_role_id <> 0';
626 $this->db->sql_query($sql);
627 $role_id = (int) $this->db->sql_fetchfield('auth_role_id');
628 if ($role_id)
629 {
630 $sql = 'SELECT role_name
631 FROM ' . ACL_ROLES_TABLE . '
632 WHERE role_id = ' . $role_id;
633 $this->db->sql_query($sql);
634 $role_name = $this->db->sql_fetchfield('role_name');
635 if (!$role_name)
636 {
637 throw new \phpbb\db\migration\exception('ROLE_ASSIGNED_NOT_EXIST', $name, $role_id);
638 }
639
640 return $this->permission_unset($role_name, $auth_option, 'role');
641 }
642
643 $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . '
644 WHERE ' . $this->db->sql_in_set('auth_option_id', $to_remove);
645 $this->db->sql_query($sql);
646 break;
647 }
648
649 $this->auth->acl_clear_prefetch();
650 }
651
652 /**
653 * {@inheritdoc}
654 */
655 public function reverse()
656 {
657 $arguments = func_get_args();
658 $original_call = array_shift($arguments);
659
660 $call = false;
661 switch ($original_call)
662 {
663 case 'add':
664 $call = 'remove';
665 break;
666
667 case 'remove':
668 $call = 'add';
669 break;
670
671 case 'permission_set':
672 $call = 'permission_unset';
673 break;
674
675 case 'permission_unset':
676 $call = 'permission_set';
677 break;
678
679 case 'role_add':
680 $call = 'role_remove';
681 break;
682
683 case 'role_remove':
684 $call = 'role_add';
685 break;
686
687 case 'role_update':
688 // Set to the original value if the current value is what we compared to originally
689 $arguments = array(
690 $arguments[1],
691 $arguments[0],
692 );
693 break;
694
695 case 'reverse':
696 // Reversing a reverse is just the call itself
697 $call = array_shift($arguments);
698 break;
699 }
700
701 if ($call)
702 {
703 return call_user_func_array(array(&$this, $call), $arguments);
704 }
705 }
706 }
707