1<?php 2 3namespace dokuwiki\plugin\virtualgroup; 4 5use dokuwiki\Logger; 6 7class VirtualGroups 8{ 9 public const CONFIG_FILE = DOKU_CONF . 'virtualgroup.conf'; 10 11 /** 12 * Get the configuration by user 13 * 14 * @return array [user => [group1, group2, ...], ...] 15 */ 16 public function getUserStructure() 17 { 18 $config = $this->loadConfig(); 19 ksort($config); 20 return $config; 21 } 22 23 /** 24 * Get the groups for a user 25 * 26 * @param string $user 27 * @return string[] 28 */ 29 public function getUserGroups($user) 30 { 31 $config = $this->loadConfig(); 32 return $config[$user] ?? []; 33 } 34 35 /** 36 * Get all users in a group 37 * 38 * @param string $group 39 * @return string[] 40 */ 41 public function getGroupUsers($group) 42 { 43 $config = $this->loadConfig(); 44 $users = []; 45 foreach ($config as $user => $groups) { 46 if (in_array($group, $groups)) { 47 $users[] = $user; 48 } 49 } 50 return $users; 51 } 52 53 54 /** 55 * Get the configuration by group 56 * 57 * @return array [group => [user1, user2, ...], ...] 58 */ 59 public function getGroupStructure() 60 { 61 $config = $this->loadConfig(); 62 $groups = []; 63 foreach ($config as $user => $usergroups) { 64 foreach ($usergroups as $group) { 65 if (!isset($groups[$group])) { 66 $groups[$group] = []; 67 } 68 $groups[$group][] = $user; 69 } 70 } 71 ksort($groups); 72 return $groups; 73 } 74 75 // region individual user/group management 76 77 /** 78 * Remove a user from all groups 79 * 80 * @param string $user 81 * @return void 82 */ 83 public function removeUser($user) 84 { 85 $config = $this->loadConfig(); 86 if (isset($config[$user])) unset($config[$user]); 87 $this->saveConfig($config); 88 } 89 90 /** 91 * Add a user to one or more groups 92 * 93 * @param string $user 94 * @param string[] $groups 95 * @return void 96 */ 97 public function addGroupsToUser($user, $groups) 98 { 99 $config = $this->loadConfig(); 100 if (!isset($config[$user])) { 101 $config[$user] = []; 102 } 103 $config[$user] = array_filter(array_unique(array_merge($config[$user], $groups))); 104 $this->saveConfig($config); 105 } 106 107 /** 108 * Set the groups for a user 109 * 110 * @param string $user 111 * @param string[] $groups 112 * @return void 113 */ 114 public function setUserGroups($user, $groups) 115 { 116 $config = $this->loadConfig(); 117 $config[$user] = array_filter($groups); 118 if ($config[$user] === []) { 119 unset($config[$user]); 120 } 121 $this->saveConfig($config); 122 } 123 124 /** 125 * Remove a group from all users 126 * 127 * @param string $group 128 * @return void 129 */ 130 public function removeGroup($group) 131 { 132 $config = $this->loadConfig(); 133 foreach ($config as $user => $groups) { 134 if (($key = array_search($group, $groups)) !== false) { 135 unset($config[$user][$key]); 136 } 137 } 138 $this->saveConfig($config); 139 } 140 141 /** 142 * Add one or more users to a group 143 * 144 * @param string $group 145 * @param string[] $users 146 * @return void 147 */ 148 public function addUsersToGroup($group, $users) 149 { 150 $config = $this->loadConfig(); 151 foreach ($users as $user) { 152 if (!isset($config[$user])) { 153 $config[$user] = []; 154 } 155 $config[$user][] = $group; 156 $config[$user] = array_filter(array_unique($config[$user])); 157 } 158 $this->saveConfig($config); 159 } 160 161 public function setGroupUsers($group, $users) 162 { 163 $config = $this->loadConfig(); 164 foreach ($users as $user) { 165 if (!isset($config[$user])) { 166 $config[$user] = []; 167 } 168 $config[$user][] = $group; 169 $config[$user] = array_filter(array_unique($config[$user])); 170 if ($config[$user] === []) { 171 unset($config[$user]); 172 } 173 } 174 $this->saveConfig($config); 175 } 176 177 // endregion 178 179 // region file management 180 181 /** 182 * Load the configuration 183 * 184 * @return array [user => [group1, group2, ...], ...] 185 */ 186 protected function loadConfig() 187 { 188 if (!file_exists(self::CONFIG_FILE)) return $this->loadLegacyConfig(); 189 190 $config = []; 191 $raw = linesToHash(file(self::CONFIG_FILE)); 192 foreach ($raw as $key => $value) { 193 $user = rawurldecode($key); 194 $groups = array_map(static fn($group) => rawurldecode(trim($group)), explode(',', $value)); 195 $config[$user] = $groups; 196 } 197 198 return $config; 199 } 200 201 /** 202 * Save the configuration 203 * 204 * @param array $config [user => [group1, group2, ...], ...] 205 * @return boolean 206 */ 207 protected function saveConfig($config) 208 { 209 global $INPUT; 210 211 $lines = [ 212 '# This file is managed by the virtualgroup plugin', 213 '# Last saved by ' . $INPUT->server->str('REMOTE_USER') . ' on ' . date('Y-m-d H:i:s'), 214 '' 215 ]; 216 foreach ($config as $user => $groups) { 217 $lines[] = auth_nameencode($user) . "\t" . 218 implode(',', array_map(static fn($group) => auth_nameencode($group), $groups)); 219 } 220 221 $ok = file_put_contents(self::CONFIG_FILE, implode("\n", $lines)); 222 if ($ok === false) { 223 msg('Failed to save virtual group configuration', -1); 224 } 225 return (bool)$ok; 226 } 227 228 /** 229 * Load the legacy configuration 230 * 231 * @return array [user => [group1, group2, ...], ...] 232 * @deprecated 233 */ 234 protected function loadLegacyConfig() 235 { 236 global $conf; 237 // determine the path to the data 238 $userFile = $conf['savedir'] . '/virtualgrp.php'; 239 240 // if there is no file we hava no data ;-) 241 if (!is_file($userFile)) return []; 242 243 // read the file 244 $content = trim(file_get_contents($userFile)); 245 246 // if its empty we have no data also 247 if (empty($content)) return []; 248 249 $users = unserialize($content); 250 // check for invalid data 251 if ($users === false) { 252 Logger::error('Failed to parse virtualgrp.php configuration file. File will be deleted.'); 253 @unlink($userFile); 254 return []; 255 } 256 257 // save in new format 258 $ok = $this->saveConfig($users); 259 if ($ok) { 260 @unlink($userFile); 261 } 262 263 return $users; 264 } 265 266 // endregion 267} 268