Форум программистов, компьютерный форум, киберфорум
PHP для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.86/7: Рейтинг темы: голосов - 7, средняя оценка - 4.86
4 / 3 / 2
Регистрация: 03.09.2013
Сообщений: 141

Организация ролей в приложении

10.12.2018, 20:06. Показов 1598. Ответов 4

Студворк — интернет-сервис помощи студентам
Здравствуйте. Если тема не по разделу - переместите
Суть: сделал организацию ролей на сайте. До этого изучал достаточно вариантов, ознакомился разными принципами.
Но пришел к своему умозаключению, суть которого и выкладываю.
Мое требование было основано на гибкости и переопределении роли, не привязываясь к группе и правах группы.
Считаю для небольшого проекта - каких большинство - это хорошее решение.
Базой стало исчерпывающий перечень привилегий и их вариаций
Код обработки не прикладываю- он в уме - но это стандартные все решения
Там метка "своё" - это значит, что если там не Null например, то эту запись/раздел/категорию может редактировать только лицо/лица, которые там указаны
Политика админа пока опущена, там оговорка другая при создании кода будет
Миниатюры
Организация ролей в приложении  
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
10.12.2018, 20:06
Ответы с готовыми решениями:

Организация ролей в приложении с разным уровнем доступа
Добрый день, хочу сделать 2 пользователя программы Только чтоб у одного не было прав для нажатия кнопок Как это прописать?

Разграничение ролей пользователей в приложении
Имеется база данных "DB" В SQL создано 3 пользователя: administrator operator user Каждый из них может открыть только свою...

Авторизация в приложении и разграничение ролей пользователей
У меня такой задача. Как сделать так чтобы когда ты открываешь от имени Админа в логин форме в Access можно было бы заходить в дизайн и...

4
4 / 3 / 2
Регистрация: 03.09.2013
Сообщений: 141
10.12.2018, 20:14  [ТС]
Чет подумал, что не надо бы в таблице привилегий описывать все варианты. Достаточно в таблице доступа просто указывать: 1,3 или 2,4 и т.п.
Миниатюры
Организация ролей в приложении  
0
 Аватар для tarasalk
1992 / 1216 / 440
Регистрация: 13.06.2013
Сообщений: 4,115
10.12.2018, 22:46
Вопрос то в чем? Нужен комментарий по вашему решению?

1) Каша.
У вас одно и тоже называется по разному. Роли / группа, права / привилегии...
То английский, то русский. Причем перевод не правильный. Permissions - это разрешения, а не роли.
Связи по стрелкам тоже не всегда правильные.

2) Гибкости не вижу.
Нет возможности привязать к юзеру несколько ролей.
Нормализация не полная (в одно поле несколько значений пишите).
Расширять не удобно. Таблица 1/2 это вообще какой-то треш.

Я бы за основу взял такой вариант.
1) users (id)
2) roles. (id, name).
3) permissions. (id, name)
4) role_permissions (id, role_id, permission_id)
5) user_permissions (id, user_id, permission_id)
6) user_roles (id, user_id, role_id)

В permissions можно добавить поля type (например категории контента / страницы контента), type_id (id категории или контента). Т.е. это полиморфная связь. Сюда же можно добавить метку "своё".
0
4 / 3 / 2
Регистрация: 03.09.2013
Сообщений: 141
30.01.2019, 23:09  [ТС]
В общем, прошло время за делами, добрался все-таки до этой реализации, несмотря на критику
Потом все оберну в фреймворк свой с доделками
В итоге я получил всю ту гибкость которую хотел, с которой и начал: чтобы был доступ по разным уровням
Чтобы был пользователь, группа, + отдельные правила допуска
Сделал пока в процедурном стиле
дано: БД
SQL
1
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
-- phpMyAdmin SQL Dump
-- version 4.8.3
-- https://www.phpmyadmin.net/
--
-- Хост: 127.0.0.1:3306
-- Время создания: Янв 30 2019 г., 22:56
-- Версия сервера: 5.7.23
-- Версия PHP: 7.2.10
 
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
 
 
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
 
--
-- База данных: `users`
--
 
-- --------------------------------------------------------
 
--
-- Структура таблицы `content_category`
--
 
CREATE TABLE `content_category` (
  `id` INT(11) NOT NULL,
  `category_name` VARCHAR(255) NOT NULL,
  `parent` INT(11) NOT NULL DEFAULT '0',
  `is_active` enum('0','1') NOT NULL DEFAULT '1' COMMENT 'По умолчанию: 1: 0 - не активна, 1 - активна',
  `access_group` VARCHAR(255) DEFAULT NULL COMMENT 'id роли / ролей таблицы role',
  `access_private` VARCHAR(255) DEFAULT NULL COMMENT 'id допустимого пользователя / пользователей из таблицы users',
  `autor` INT(11) NOT NULL,
  `date_create` datetime NOT NULL,
  `date_change` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
--
-- Дамп данных таблицы `content_category`
--
 
INSERT INTO `content_category` (`id`, `category_name`, `parent`, `is_active`, `access_group`, `access_private`, `autor`, `date_create`, `date_change`) VALUES
(1, 'cat-1', 0, '1', '2', NULL, 2, '2019-01-07 00:00:00', '2019-01-07 00:00:00'),
(2, 'value3', 0, '0', NULL, NULL, 0, '2019-01-01 00:00:00', '2019-01-01 00:00:00');
 
-- --------------------------------------------------------
 
--
-- Структура таблицы `privelege`
--
 
CREATE TABLE `privelege` (
  `id` INT(11) NOT NULL,
  `action` VARCHAR(255) NOT NULL,
  `description` VARCHAR(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
--
-- Дамп данных таблицы `privelege`
--
 
INSERT INTO `privelege` (`id`, `action`, `description`) VALUES
(1, 'С', 'создание'),
(2, 'R', 'чтение'),
(3, 'U', 'редактирование'),
(4, 'D', 'удаление');
 
-- --------------------------------------------------------
 
--
-- Структура таблицы `role`
--
 
CREATE TABLE `role` (
  `id` INT(11) NOT NULL COMMENT 'зависимые таблицы: users',
  `description` VARCHAR(255) NOT NULL,
  `tag` enum('admin','moderator','user','guest') NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='главная для users, user_privelege';
 
--
-- Дамп данных таблицы `role`
--
 
INSERT INTO `role` (`id`, `description`, `tag`) VALUES
(1, 'Администратор', 'admin'),
(2, 'Модератор', 'moderator'),
(3, 'Пользователь', 'user'),
(4, 'Гость', 'guest');
 
-- --------------------------------------------------------
 
--
-- Структура таблицы `users`
--
 
CREATE TABLE `users` (
  `id` INT(11) NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `login` VARCHAR(255) NOT NULL,
  `email` VARCHAR(255) NOT NULL,
  `password` VARCHAR(255) NOT NULL,
  `session` VARCHAR(255) DEFAULT NULL,
  `user_browser` VARCHAR(255) DEFAULT NULL,
  `role_id` INT(11) NOT NULL COMMENT 'зависимый от role: id',
  `is_active` VARCHAR(255) NOT NULL DEFAULT '0' COMMENT '0 - не активен, 1 - активен',
  `only_my_article` enum('0','1') NOT NULL DEFAULT '0' COMMENT '0 - false / 1 - true'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='зависимая от role / главная для user_privelege';
 
--
-- Дамп данных таблицы `users`
--
 
INSERT INTO `users` (`id`, `name`, `login`, `email`, `password`, `session`, `user_browser`, `role_id`, `is_active`, `only_my_article`) VALUES
(2, 'moder', 'moder', 'moder@moder.ru', 'moder', NULL, NULL, 2, '1', '1'),
(3, 'admin', 'admin', 'admin@admin.ru', 'admin', NULL, NULL, 1, '1', '0');
 
-- --------------------------------------------------------
 
--
-- Структура таблицы `user_privelege_cache`
--
 
CREATE TABLE `user_privelege_cache` (
  `id` INT(11) NOT NULL,
  `users_id` INT(11) NOT NULL COMMENT 'ID юзера. Зависимый от users: id',
  `module` VARCHAR(255) NOT NULL COMMENT 'модуль сайта',
  `privelege_id` VARCHAR(255) DEFAULT NULL,
  `my_only` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Только свои: 0 - нет / false, 1 - да / true, 0 - default'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='зависимая от users';
 
--
-- Дамп данных таблицы `user_privelege_cache`
--
 
INSERT INTO `user_privelege_cache` (`id`, `users_id`, `module`, `privelege_id`, `my_only`) VALUES
(1, 2, 'content_category', '2,3', 0),
(3, 2, 'news', '1', 0);
 
--
-- Индексы сохранённых таблиц
--
 
--
-- Индексы таблицы `content_category`
--
ALTER TABLE `content_category`
  ADD PRIMARY KEY (`id`);
 
--
-- Индексы таблицы `privelege`
--
ALTER TABLE `privelege`
  ADD PRIMARY KEY (`id`);
 
--
-- Индексы таблицы `role`
--
ALTER TABLE `role`
  ADD PRIMARY KEY (`id`);
 
--
-- Индексы таблицы `users`
--
ALTER TABLE `users`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `role_id` (`role_id`);
 
--
-- Индексы таблицы `user_privelege_cache`
--
ALTER TABLE `user_privelege_cache`
  ADD PRIMARY KEY (`id`),
  ADD KEY `FK_user_privelege_users_id` (`users_id`);
 
--
-- AUTO_INCREMENT для сохранённых таблиц
--
 
--
-- AUTO_INCREMENT для таблицы `content_category`
--
ALTER TABLE `content_category`
  MODIFY `id` INT(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
 
--
-- AUTO_INCREMENT для таблицы `privelege`
--
ALTER TABLE `privelege`
  MODIFY `id` INT(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
 
--
-- AUTO_INCREMENT для таблицы `role`
--
ALTER TABLE `role`
  MODIFY `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'зависимые таблицы: users', AUTO_INCREMENT=5;
 
--
-- AUTO_INCREMENT для таблицы `users`
--
ALTER TABLE `users`
  MODIFY `id` INT(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
 
--
-- AUTO_INCREMENT для таблицы `user_privelege_cache`
--
ALTER TABLE `user_privelege_cache`
  MODIFY `id` INT(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
 
--
-- Ограничения внешнего ключа сохраненных таблиц
--
 
--
-- Ограничения внешнего ключа таблицы `users`
--
ALTER TABLE `users`
  ADD CONSTRAINT `FK_users_role_id` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
 
--
-- Ограничения внешнего ключа таблицы `user_privelege_cache`
--
ALTER TABLE `user_privelege_cache`
  ADD CONSTRAINT `FK_user_privelege_users_id` FOREIGN KEY (`users_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
COMMIT;
 
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
PHP
1
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
<?php
 
// http://php.net/manual/ru/function.session-name.php
session_name();
 
session_start();
 
echo '<pre>';
 
$host = 'localhost'; // адрес сервера
$database = 'users'; // имя базы данных
$user = 'root'; // имя пользователя
$password = ''; // пароль
$link = mysqli_connect($host, $user, $password, $database);
 
// id юзера, пока вручную, потом через отдельный запрос или через куки
$user_id = 2;
 
// таблица с которой потом будет работать модель
$table = 'content_category';
 
// подтягиваем информацию о юзере
$query1 = "
SELECT
*
FROM
users
INNER JOIN
role
ON
users.role_id = role.id
WHERE 
users.id = {$user_id}
";
$result1 = mysqli_query($link, $query1) or die("Ошибка " . mysqli_error($link));
$row_cnt1 = $result1->num_rows;
if ($row_cnt1 !=0) {
    $array1 = [];
    foreach ($result1 as $res1) {
        // $array1[]['user_info'] = $res1;
        $array1[] = $res1;
        // var_dump($array1);
    }
} else {
    echo "Пользователя с идентификатором $user_id - не существует";
    return false;
}
 
// подтягиваем информацию о привелегиях юзера
$query2 = "
SELECT
*
FROM
user_privelege_cache
WHERE
users_id = $user_id
";
// можно добавить условие о выборке конкретного модуля, равного $table
// AND
// module = '$table'
// подумать, лучше скорее всего, оставить ВСЕ в сессии и куки всю информацию, чтобы не нагружать сервер запросами
// в куки не вариант, большой размер
// можно добавить кэш-таблицу с идентификатором сессии и всеми данными + срок хранения = сроку куки, затем автоудаление / обновление
 
$result2 = mysqli_query($link, $query2) or die("Ошибка " . mysqli_error($link));
$row_cnt2 = $result2->num_rows;
if ($row_cnt2 !=0) {
    $array2 = [];
    foreach ($result2 as $res2) {
        // $array2[]['privelege'] = $res2;
        $array2[] = $res2;
        // var_dump($res2);
    }
    $result_for_union_session = array_merge($array1, $array2);
} else {
    $result_for_union_session = $array1;
}
// var_dump($result_for_union_session);
 
// запихиваем всю информацию в сессию
$_SESSION['user_info'] = $result_for_union_session;
var_dump($_SESSION['user_info']);
 
$query3 = "
SELECT
*
FROM 
{$table}
";
$result3 = mysqli_query($link, $query3) or die("Ошибка " . mysqli_error($link));
$i=0; // для счетчика прохода по массиву
foreach ($result3 as $res3) {
    $i++;
    // проверяем активность страниц
    echo '<p>';
    echo '<b>активность страниц</b>';
    echo '<p>';
    if ($res3['is_active'] == 1) {
        echo "Страница ".$res3['category_name']." активна <p>";
    } else {
        // return false;
        echo "Страница ".$res3['category_name']." не активна <p>";
    }
 
    echo '<p>';
 
    // проверяем доступ группы: access_group
    echo '<p>';
    echo '<b>доступ группы: access_group</b>';
    echo '<p>';
    if ($res3['access_group'] !== null) {
        // разбиваем в массив значения доступа группы из таблицы модуля
        $access_group = explode(',', $res3['access_group']);
        // var_dump($access_group);
        if ((in_array($_SESSION['user_info'][0]['role_id'], $access_group)) || $_SESSION['user_info'][0]['tag'] == 'admin') {
            echo "Доступ группы ".$_SESSION['user_info'][0]['description']." к ограниченной странице ".$res3['category_name']." разрешен (access_group) <p>";
        } else {
            // return false;
            echo "Доступ группы ".$_SESSION['user_info'][0]['description']." к ограниченной странице ".$res3['category_name']." запрещен (access_group) <p>";
            $err = [];
        }
    } else {
        echo "Страница ".$res3['category_name']." доступна всем группам пользователей<p>";
    }
 
    // проверяем доступ конкретной привелегии: access_private
    echo '<p>';
    echo '<b>доступ конкретной привелегии: access_private</b>';
    echo '<p>';
    if ($res3['access_private'] !== null) {
        // разбиваем в массив значения доступа конкретной привелегии из таблицы модуля
        $access_private = explode(',', $res3['access_private']);
        if ((in_array($_SESSION['user_info'][0]['id'], $access_private)) || $_SESSION['user_info'][0]['tag'] == 'admin') {
            echo "Доступ юзера (ID: ".$_SESSION['user_info'][0]['id']." name: ".$_SESSION['user_info'][0]['name'].") к ограниченной странице ".$res3['category_name']." разрешен (access_private) <p>";
        } else {
            // return false;
            echo "Доступ юзера (ID: ".$_SESSION['user_info'][0]['id']." name: ".$_SESSION['user_info'][0]['name'].") к ограниченной странице ".$res3['category_name']." запрещен (access_private) <p>";
            $err = [];
        }
    } else {
        echo "Доступ к странице не привязан к конкретному пользователю (столбец 'access_private')";
    }
 
    // проверяем доступ с к своим статьям
    echo '<p>';
    echo '<b>доступ с к своим статьям</b>';
    echo '<p>';
 
    if ($_SESSION['user_info'][0]['only_my_article'] !=0) {
        echo 'Только свои статьи - ДА / ' . $_SESSION['user_info'][0]['only_my_article'];
        echo '<p>';
        if ($_SESSION['user_info'][0]['id'] != $res3['autor']) {
            echo 'Допуск к статье запрещен';
            $err = [];
            // $err[] = " описание ошибки ";
        } else {
            echo 'Допуск к статье разрешен';
        }
    } else {
        echo 'Только свои статьи - НЕТ / ' . $_SESSION['user_info'][0]['only_my_article'];
    }
 
    echo '<p>';
    echo '<b>Итоговая оценка доступа: </b>';
    if (isset ($err)) {
        echo '<p>';
        echo '<b><div style="color: #C20000;">Доступ запрещен </div></b>';
        /*
        foreach ($err as $e) {
            echo " <div style=\"background-color: #FF0000;\"><b>$e</b></div><br> ";
        }
        */
    } else {
        echo '<p>';
        echo '<b><div style="color: #00C21B;">Доступ разрешен </div></b>';
    }
 
    echo '<p>';
 
    // ПРАВА: чтение, запись ...!
    echo 'ПРАВА: чтение, запись ...';
    echo '<p>';
    // var_dump($_SESSION['user_info'][$i]['privelege_id']);
    // $p_arr = array($_SESSION['user_info'][$i]['privelege_id']);
    // var_dump($p_arr);
    $p_arr = explode(',', $_SESSION['user_info'][$i]['privelege_id']);
    // var_dump($p_arr);
    foreach ($p_arr as $value) {
        $query3 = "
        SELECT
        *
        FROM privelege
        WHERE
        id = $value
        ";
        $result3 = mysqli_query($link, $query3) or die("Ошибка " . mysqli_error($link));
        foreach ($result3 as $res) {
            echo '<button>' . $res['description'] . '</button>';
        }
    }
 
    echo '<p>';
    echo '-------------------';
    echo '<p>';
}
 
// не забыть, что доделать в фреймворке:
// нельзя удалить администратора, если их один
// нельзя ставить доступ конкретной привелегии (access_private), если пользователь не относится к группе допуска (access_group)
// можно создать массив зо значениями true / false (или иная метка) по каждому проходу и если есть в нем false - то отказ
// вообще потом первую часть [0] - в БД а остальное запрашивать, подумать
// не забыть добавить об админе условие ||
прикрепил все в архиве, + файл dbForge Studio "Диаграмма1", кому удобнее
надеюсь, кому-нибудь пригодится для идей и заточки
Вложения
Тип файла: zip users.zip (183.8 Кб, 8 просмотров)
0
4 / 3 / 2
Регистрация: 03.09.2013
Сообщений: 141
21.03.2019, 20:27  [ТС]
В общем, добил тему, как хотелось, доработал недостатки
Админка пока не готова, ручками в БД придется проверять
В итоге (комментарии - мусор, можно удалить):
PHP
1
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
// http://framework-development/testquery
// TODO: OK - перепроверить каскадное удаление
 
class UserAccess extends Model {
 
    // таблица-модуль сайта
    // обязательно передавать при вызове класса
    // закомментировать при завершении, т.к. свойство является наследуемым
    protected $table = 'module_content_category';
 
    // информация о пользователе и его правах, доступах
    // private $userInfo;
 
    // флаг проходимости
    // TODO: пока не использован, предполагается в итоговой оценке
    private $access = false;
 
    // допустимые действия: создание, чтение, редактирование, удаление
    private $action = [];
 
    // обязательные поля которые должны присутствовать в таблице модуля БД
    private $fieldTableDb = [
        'is_active' => 'is_active',
        'access_group' => 'access_group',
        'access_private' => 'access_private',
        'author' => 'author',
    ];
 
    public function __construct($table = '') {
        parent::__construct();
        // TODO: расскоментировать по завершении
        $this->table = ($table) ? '$table' : self::setTableModel();
    }
 
    // $pageId - Id страницы соответственно передать как часть роутера строки запроса URL
    // если не передана из контроллера, осуществляет поиск прав, действий и допусков в массиве всех строк таблицы
    public function getAccess($pageId = '') {
 
        // TODO: расскоментировать по окончании
        if ($this->table && self::checkIssetTable() && self::checkIssetField() && $_SESSION[AUTH_SESSION]) {
        // if ($this->table && self::checkIssetTable() && self::checkIssetField()) {
 
            // $userBaseInfoSql
            // возвращаем базовую информацию о пользователе типа:
            //    Array
            //    (
            //        [0] => Array
            //            (
            //                [id] => 51
            //                [description] => Администратор
            //                [tag] => admin
            //                [role_id] => 1
            //                [only_my_article] => 1
            //            )
            //    )
            // почему так, не сразу сбор данных из сессии?
            // потому что во время активной сессии статус пользователя может поменять лицо, обладающее соответствующими правами
            // лишняя проверка не повредит даже
            // return array
            $userBaseInfoSql = $this->queryFetch("
            SELECT
            users_role.*,
            users_users.id,
            users_users.role_id,
            users_users.only_my_article
            FROM users_users
            INNER JOIN users_role
            ON users_users.role_id = users_role.id
            WHERE users_users.id = ?
            AND users_users.is_active = ?
            ", [$_SESSION[AUTH_SESSION]['id'],1]);
            // 51 - admin
            // 5 - moder
            // TODO: $_SESSION[AUTH_SESSION]['id']
            // debug($userBaseInfoSql);
            $userBaseInfo = $userBaseInfoSql[0];
            // debug($userBaseInfo);
            // todo: OK - при пустом массиве (users_users.is_active = 0) также отрабатывает. сделать условие, если массив не пустой (NULL)
 
            // $fieldTableDb = implode(',', $this->fieldTableDb);
 
            // условие о выборке конкретной страницы, если она была передана
            // $pageId = 3;
            if ($pageId) {
                $where = 'WHERE id = ?';
                $id = $pageId;
            }
            $resQueryModulePages = $this->queryFetch("SELECT * FROM {$this->table} $where", [$id]); // todo: OK - предусмотреть привязку к конкретной странице
            // debug($resQueryModulePages);
 
            // проходимся по массиву страниц / столбцов модуля
            // $i=0; // для счетчика прохода по массиву прав чтение, запись ...
            foreach ($resQueryModulePages as $modulePage) {
 
                // debug($modulePage);
 
                //
                // проверяем доступ группы: access_group
                //
                // echo '<p><b>доступ группы: access_group</b></p>';
 
                if ($modulePage['access_group'] !==null) {
                    // разбиваем в массив значения доступа группы из таблицы модуля
                    $access_group = explode(',', $modulePage['access_group']);
                    // debug($access_group);
                    if ((!in_array($userBaseInfo['role_id'], $access_group))) {
                        $err = [];
                    }
                }
                // потом сократить код else
 
                //
                // проверяем доступ конкретной привелегии: access_private
                //
                // echo '<p><b>доступ конкретной привелегии: access_private</b></p>';
                if ($modulePage['access_private'] !==null) {
                    $access_private = explode(',', $modulePage['access_private']);
                    // debug($access_private);
                    if ((!in_array($userBaseInfo['id'], $access_private))) {
                        $err = [];
                    }
                }
                // потом сократить код else
 
                //
                // проверяем доступ с к своим статьям todo: доработать с меткой "только свои"
                //
                // echo '<p><b>доступ с к своим статьям</b></p>';
                if ($userBaseInfo['only_my_article'] !=0) {
                    // echo 'Только свои статьи - ДА=1 / НЕТ=0: ' . $userBaseInfo['only_my_article'];
                    if ($userBaseInfo['id'] != $modulePage['author']) {
                        $err = [];
                        // $err[] = " описание ошибки ";
                    }
                }
 
                // echo '<p><b>Итоговая оценка доступа (по циклу статьи):</b></p>';
                if (isset($err) && $userBaseInfo['tag'] !== 'admin') {
                    // echo '<p>';
                    // echo '<b><div style="color: #C20000;">Доступ запрещен </div></b>';
                    // foreach ($err as $e) {
                    //     echo " <div style=\"background-color: #FF0000;\"><b>$e</b></div><br> ";
                    // }
                    // self::accessDeniedView();
                    if ($pageId) {
                        self::accessDeniedView();
                    }
                } else {
                    debug($modulePage);
                    echo '<p>';
                    echo '<b><div style="color: #00C21B;">Доступ разрешен </div></b>';
                    // echo '<p><b>ПРАВА: чтение, запись ...</b></p>';
                    if ($userBaseInfo['tag'] == 'admin') {
                        $resAction = $this->queryFetch("SELECT * FROM users_privelege");
                        $this->action = $resAction;
                        foreach ($resAction as $action) {
                            echo '<button>' . $action['description'] . '</button>';
                        }
                    } else {
                        $getPrivelege = $this->queryFetch("SELECT * FROM users_privelege_cache WHERE users_id = ? AND module = ?", [$userBaseInfo['id'], $this->table]);
                        // var_dump($getPrivelege);
                        if (!empty($getPrivelege)) {
                            // debug($getPrivelege);
                            $arrAction = explode(',', $getPrivelege[0]['privelege_id']);
                            // $arrAction[] = 2; // добавление действия как чтение, раз допустимы другие todo: нет, лучше добавлять чтение при присоении прав
                            // debug($arrAction);
                            $actionArr = [];
                            foreach ($arrAction as $item) {
                                $resAction = $this->queryFetch("SELECT * FROM users_privelege WHERE id =?", [$item]);
                                foreach ($resAction as $action) {
                                    echo '<button>' . $action['description'] . '</button>';
                                    $actionArr[] = $action['action'];
                                }
                                $this->action = $actionArr;
                            }
                        }
                        $this->access = true;
                    }
                }
                unset($err);
            }
        } else {
            if ($pageId) {
                $and = 'AND id = ?';
                $id = $pageId;
            }
            $resQueryModulePages = $this->queryFetch("SELECT * FROM {$this->table} WHERE {$this->fieldTableDb['is_active']} !=0 AND {$this->fieldTableDb['access_group']} IS NULL $and", [$id]);
            debug('GUEST PAGE');
            if (!empty($resQueryModulePages)) {
                debug($resQueryModulePages);
            } else {
                self::accessDeniedView();
            }
            // todo: OK - не отсеял ограничения групп
        }
    }
 
    public function getAction() {
        return $this->action;
    }
 
    public function accessResult() {
        return $this->access;
    }
 
    private function accessDeniedView() {
        http_response_code(403);
        $errorController = new Page403();
        $errorController->getView();
        die();
    }
 
    // это случай, когда мы можем подтянуть имя таблицы модуля,
    // если она задана в конструкторе модели контроллера
    // в ином случае нам нужно будет явно передавать имя таблицы, с которой будет работать класс
    // возвращает имя таблицы-модуля через метод getTable() родительского класса core/Model.php
    private function setTableModel() {
        try {
            $model = Router::getController() . 'Model';
            $obj = new $model;
            return $obj->getTable(); // метод core/Model.php вернуть имя таблицы
        } catch (Throwable $t) {
            http_response_code(404);
            debug('Сообщение от lib/UserAccess.php (setTableModel()): Класса ' . $model . ' для подключения таблицы модуля - не существует');
            debug($t->getMessage());
            return false;
        }
    }
 
    // функция наличия таблицы модуля
    // в принципе, чевидно и при создании модели, движок РНР сам сообщит
    // здесь реализация пока не нужна. напишем при необходимости
    // тогда CREATE TABLE IF NOT EXISTS table_name - не тут вообще
    private function checkIssetTable() {
        $isset = $this->queryFetch("SHOW TABLES LIKE ?", [$this->table]);
        if ($isset == null) {
            debug('Сообщение от lib/UserAccess.php (checkIssetTable()): таблицы '.$this->table.' не существует');
            return false;
        } else {
            return true;
        }
    }
 
    // функция проверки наличия обязательных полей таблицы модуля
    private function checkIssetField() {
        try {
            $fieldTableDb = implode(',', $this->fieldTableDb);
            $this->queryFetch("SELECT {$fieldTableDb} FROM {$this->table}");
            return true;
        } catch (Throwable $t) {
            http_response_code(404);
            debug('Сообщение от lib/UserAccess.php (checkIssetField()): отсутствуют обязательные поля в таблице '.$this->table.' ');
            debug($t->getMessage());
            return false;
        }
    }
 
    // не забыть, что доделать в фреймворке:
    // нельзя удалить администратора, если их один
    // нельзя ставить доступ конкретной привелегии (access_private), если пользователь не относится к группе допуска (access_group)
    // можно создать массив зо значениями true / false (или иная метка) по каждому проходу и если есть в нем false - то отказ
    // вообще потом первую часть [0] - в БД а остальное запрашивать, подумать
    // не забыть добавить об админе условие ||
}
И БД
SQL
1
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
-- phpMyAdmin SQL Dump
-- version 4.8.3
-- https://www.phpmyadmin.net/
--
-- Хост: 127.0.0.1:3306
-- Время создания: Мар 21 2019 г., 20:20
-- Версия сервера: 5.7.23
-- Версия PHP: 7.2.10
 
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
 
 
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
 
--
-- База данных: `development`
--
 
-- --------------------------------------------------------
 
--
-- Структура таблицы `module_content_category`
--
 
CREATE TABLE `module_content_category` (
  `id` INT(11) NOT NULL,
  `title` VARCHAR(255) NOT NULL,
  `parent` tinyint(4) NOT NULL DEFAULT '0',
  `is_active` tinyint(4) NOT NULL DEFAULT '1' COMMENT 'По умолчанию: 1: 0 - не активна, 1 - активна',
  `access_group` VARCHAR(255) DEFAULT NULL COMMENT 'id роли / ролей таблицы users_role',
  `access_private` VARCHAR(255) DEFAULT NULL COMMENT 'id допустимого пользователя / пользователей из таблицы users_users',
  `author` INT(11) NOT NULL,
  `date_create` datetime DEFAULT NULL,
  `date_change` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
--
-- Дамп данных таблицы `module_content_category`
--
 
INSERT INTO `module_content_category` (`id`, `title`, `parent`, `is_active`, `access_group`, `access_private`, `author`, `date_create`, `date_change`) VALUES
(2, 'title-2', 0, 1, NULL, NULL, 67, '2019-03-20 00:00:00', NULL);
 
-- --------------------------------------------------------
 
--
-- Структура таблицы `test_query_table`
--
 
CREATE TABLE `test_query_table` (
  `id` INT(11) NOT NULL,
  `alias` VARCHAR(255) DEFAULT NULL,
  `content` text,
  `autor` VARCHAR(255) DEFAULT NULL,
  `category` INT(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
--
-- Дамп данных таблицы `test_query_table`
--
 
INSERT INTO `test_query_table` (`id`, `alias`, `content`, `autor`, `category`) VALUES
(211, 'ssssssss', 'ssssssss', 'sssssssss', NULL),
(212, 'ssssssss', 'ssssssss', 'sssssssss', NULL),
(213, 'ssssssss', 'ssssssss', 'sssssssss', NULL),
(214, 'ssssssss', 'ssssssss', 'sssssssss', NULL),
(215, 'ssssssss', 'ssssssss', 'sssssssss', NULL),
(216, 'param1', 'param2', 'param3', NULL),
(217, 'param1', 'param2', 'param3', NULL);
 
-- --------------------------------------------------------
 
--
-- Структура таблицы `users_privelege`
--
 
CREATE TABLE `users_privelege` (
  `id` INT(11) NOT NULL,
  `action` VARCHAR(255) NOT NULL,
  `description` VARCHAR(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
--
-- Дамп данных таблицы `users_privelege`
--
 
INSERT INTO `users_privelege` (`id`, `action`, `description`) VALUES
(1, 'create', 'создание'),
(2, 'read', 'чтение'),
(3, 'update', 'редактирование'),
(4, 'delete', 'удаление');
 
-- --------------------------------------------------------
 
--
-- Структура таблицы `users_privelege_cache`
--
 
CREATE TABLE `users_privelege_cache` (
  `id` INT(11) NOT NULL,
  `users_id` INT(11) NOT NULL COMMENT 'ID юзера. Зависимый от users_users: id',
  `module` VARCHAR(255) NOT NULL COMMENT 'модуль сайта',
  `privelege_id` VARCHAR(255) DEFAULT NULL COMMENT 'перечень привилегий: чтение, создание, редактирование, удаление',
  `my_only` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Только свои: 0 - нет / false, 1 - да / true, 0 - default'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
--
-- Дамп данных таблицы `users_privelege_cache`
--
 
INSERT INTO `users_privelege_cache` (`id`, `users_id`, `module`, `privelege_id`, `my_only`) VALUES
(2, 51, 'module_content_category', NULL, 0);
 
-- --------------------------------------------------------
 
--
-- Структура таблицы `users_role`
--
 
CREATE TABLE `users_role` (
  `id` INT(11) NOT NULL COMMENT 'зависимые таблицы: users_users',
  `description` VARCHAR(255) NOT NULL,
  `tag` VARCHAR(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='главная для users, user_privelege';
 
--
-- Дамп данных таблицы `users_role`
--
 
INSERT INTO `users_role` (`id`, `description`, `tag`) VALUES
(1, 'Администратор', 'admin'),
(2, 'Модератор', NULL),
(3, 'Пользователь', NULL);
 
-- --------------------------------------------------------
 
--
-- Структура таблицы `users_users`
--
 
CREATE TABLE `users_users` (
  `id` INT(11) NOT NULL,
  `name` VARCHAR(50) NOT NULL,
  `login` VARCHAR(255) NOT NULL,
  `email` VARCHAR(50) NOT NULL,
  `password` VARCHAR(255) NOT NULL,
  `session` VARCHAR(255) DEFAULT NULL,
  `browser` VARCHAR(255) DEFAULT NULL,
  `role_id` INT(11) NOT NULL COMMENT 'зависимый от users_role: id',
  `is_active` enum('0','1') NOT NULL DEFAULT '0' COMMENT '0 - не активен, 1 - активен',
  `register_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'для удаления при отсутствии подтверждения через Х дней и для информации',
  `only_my_article` enum('0','1') NOT NULL DEFAULT '0' COMMENT '0 - false / 1 - true',
  `confirm_code` VARCHAR(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
--
-- Дамп данных таблицы `users_users`
--
 
INSERT INTO `users_users` (`id`, `name`, `login`, `email`, `password`, `session`, `browser`, `role_id`, `is_active`, `register_date`, `only_my_article`, `confirm_code`) VALUES
(49, 'xzvxzcvxzcx', 'xzvxzcvxzcx', 'xzv@zcvxz.cx', '$2y$10$vVycJcmvwXaMWzXHSqwfF.ajOMbouJzafzsMhY9E3mQMaPdm51SCq', NULL, NULL, 3, '0', '2019-02-20 02:18:08', '0', '0766a9c6ff'),
(51, 'Администратор', 'admin', 'admin@admin.ru', '$2y$10$y3HaqkLGwCwu.OZ9T9gxHu5FjJ89vfTQ1XK8gm8RXXdfNSPYoBHDK', 'a597e50502f5ff68e3e25b9114205d4a', 'Mozilla (Windows NT 6.1; Win64; x64) AppleWebKit (KHTML, like Gecko) Chrome Safari OPR', 1, '1', '2019-02-21 00:10:58', '1', '39ddb6adb6'),
(52, 'qqqqqq', 'qqqqqq', 'qqqqqq@qqqqqq.qqqqqq', '$2y$10$oUCBorfJMW87rjva2JRqX.8278wyZp1rJJp7ximtYB9muAPiNOmqK', NULL, NULL, 3, '1', '2019-02-24 18:49:10', '0', '0b3dde00aa'),
(67, 'asdfasdfasdfs', 'asdfasdfasdfs', 'asdfa@sdfas.dfs', '$2y$10$57kEm6egb7nHryWtnKKTqu8zYg/KcPdvnAUgL94y9un4o92JoB6z6', NULL, NULL, 1, '1', '2019-03-11 22:57:30', '0', '8431e9c1f1');
 
--
-- Индексы сохранённых таблиц
--
 
--
-- Индексы таблицы `module_content_category`
--
ALTER TABLE `module_content_category`
  ADD PRIMARY KEY (`id`),
  ADD KEY `FK_module_content_category_users_users_id` (`author`);
 
--
-- Индексы таблицы `test_query_table`
--
ALTER TABLE `test_query_table`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `id` (`id`),
  ADD KEY `id_2` (`id`),
  ADD KEY `id_3` (`id`);
 
--
-- Индексы таблицы `users_privelege`
--
ALTER TABLE `users_privelege`
  ADD PRIMARY KEY (`id`);
 
--
-- Индексы таблицы `users_privelege_cache`
--
ALTER TABLE `users_privelege_cache`
  ADD PRIMARY KEY (`id`),
  ADD KEY `FK_users_privelege_cache_users_users_id` (`users_id`);
 
--
-- Индексы таблицы `users_role`
--
ALTER TABLE `users_role`
  ADD PRIMARY KEY (`id`);
 
--
-- Индексы таблицы `users_users`
--
ALTER TABLE `users_users`
  ADD PRIMARY KEY (`id`),
  ADD KEY `FK_users_users_users_role_id` (`role_id`);
 
--
-- AUTO_INCREMENT для сохранённых таблиц
--
 
--
-- AUTO_INCREMENT для таблицы `module_content_category`
--
ALTER TABLE `module_content_category`
  MODIFY `id` INT(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
 
--
-- AUTO_INCREMENT для таблицы `test_query_table`
--
ALTER TABLE `test_query_table`
  MODIFY `id` INT(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=218;
 
--
-- AUTO_INCREMENT для таблицы `users_privelege`
--
ALTER TABLE `users_privelege`
  MODIFY `id` INT(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
 
--
-- AUTO_INCREMENT для таблицы `users_privelege_cache`
--
ALTER TABLE `users_privelege_cache`
  MODIFY `id` INT(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
 
--
-- AUTO_INCREMENT для таблицы `users_role`
--
ALTER TABLE `users_role`
  MODIFY `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'зависимые таблицы: users_users', AUTO_INCREMENT=4;
 
--
-- AUTO_INCREMENT для таблицы `users_users`
--
ALTER TABLE `users_users`
  MODIFY `id` INT(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=68;
 
--
-- Ограничения внешнего ключа сохраненных таблиц
--
 
--
-- Ограничения внешнего ключа таблицы `module_content_category`
--
ALTER TABLE `module_content_category`
  ADD CONSTRAINT `FK_module_content_category_users_users_id` FOREIGN KEY (`author`) REFERENCES `users_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
 
--
-- Ограничения внешнего ключа таблицы `users_privelege_cache`
--
ALTER TABLE `users_privelege_cache`
  ADD CONSTRAINT `FK_users_privelege_cache_users_users_id` FOREIGN KEY (`users_id`) REFERENCES `users_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
 
--
-- Ограничения внешнего ключа таблицы `users_users`
--
ALTER TABLE `users_users`
  ADD CONSTRAINT `FK_users_users_users_role_id` FOREIGN KEY (`role_id`) REFERENCES `users_role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
COMMIT;
 
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
Из контроллера вызывается:
PHP
1
2
3
4
5
6
7
8
9
10
11
  $u = new UserAccess();
        // debug($u);
        $u->getAccess();
        $action = $u->getAction();
        debug('action: ');
        debug($action);
        $access = $u->accessResult();
        var_dump($access);
        if ($access) {
            echo '$access OOOKKK';
        }
Получаем действия (редактирование, удаление и пр.) и общая оценка доступа
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
21.03.2019, 20:27
Помогаю со студенческими работами здесь

Создание авторизации в приложении с организацией ролей пользователей
Доброго времени суток. Скажите пожалуйста, что нужно для создания авторизации... То есть суть проекта: есть клиент - ему...

Организация вывода данных в приложении
Добрый вечер. Решил создать базу данных и приложение на Visual C++ для выборки данных и вставки их в форму Microsoft Word и столкнулся с...

Организация приоритета окон в приложении
Здравствуйте господа. Возник очередной вопрос. В организации отображения окон. Как бы это выразить... В их послойном управлении,...

Организация авторизации в MVC3 приложении
Дано: удаленная БД MySQL; соединение с БД сделал. теперь необходимо организовать авторизацию в приложении MVC3 и связать ее...

Организация двух потоков в приложении
Ребят не могу допереть у меня есть многопоточное приложение. И в одном из потоков я формирую данные в рекурсии. И надо создать еще 1 поток...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru