1f4476bd9SJan Schumann<?php 2f4476bd9SJan Schumann 3f4476bd9SJan Schumann/** 4f4476bd9SJan Schumann * Plaintext authentication backend 5f4476bd9SJan Schumann * 6f4476bd9SJan Schumann * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 7f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 8f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 9f4476bd9SJan Schumann * @author Jan Schumann <js@schumann-it.com> 10f4476bd9SJan Schumann */ 11*5aa905e9SAndreas Gohrclass auth_plugin_authplain extends DokuWiki_Auth_Plugin 12*5aa905e9SAndreas Gohr{ 13311f4603SAndreas Gohr /** @var array user cache */ 14311f4603SAndreas Gohr protected $users = null; 15311f4603SAndreas Gohr 16311f4603SAndreas Gohr /** @var array filter pattern */ 17*5aa905e9SAndreas Gohr protected $pattern = array(); 18f4476bd9SJan Schumann 196c8c1f46SChristopher Smith /** @var bool safe version of preg_split */ 20*5aa905e9SAndreas Gohr protected $pregsplit_safe = false; 216c8c1f46SChristopher Smith 22f4476bd9SJan Schumann /** 23f4476bd9SJan Schumann * Constructor 24f4476bd9SJan Schumann * 25f4476bd9SJan Schumann * Carry out sanity checks to ensure the object is 26f4476bd9SJan Schumann * able to operate. Set capabilities. 27f4476bd9SJan Schumann * 28f4476bd9SJan Schumann * @author Christopher Smith <chris@jalakai.co.uk> 29f4476bd9SJan Schumann */ 30*5aa905e9SAndreas Gohr public function __construct() 31*5aa905e9SAndreas Gohr { 32454d868bSAndreas Gohr parent::__construct(); 33f4476bd9SJan Schumann global $config_cascade; 34f4476bd9SJan Schumann 35f4476bd9SJan Schumann if (!@is_readable($config_cascade['plainauth.users']['default'])) { 36f4476bd9SJan Schumann $this->success = false; 37f4476bd9SJan Schumann } else { 38f4476bd9SJan Schumann if (@is_writable($config_cascade['plainauth.users']['default'])) { 39f4476bd9SJan Schumann $this->cando['addUser'] = true; 40f4476bd9SJan Schumann $this->cando['delUser'] = true; 41f4476bd9SJan Schumann $this->cando['modLogin'] = true; 42f4476bd9SJan Schumann $this->cando['modPass'] = true; 43f4476bd9SJan Schumann $this->cando['modName'] = true; 44f4476bd9SJan Schumann $this->cando['modMail'] = true; 45f4476bd9SJan Schumann $this->cando['modGroups'] = true; 46f4476bd9SJan Schumann } 47f4476bd9SJan Schumann $this->cando['getUsers'] = true; 48f4476bd9SJan Schumann $this->cando['getUserCount'] = true; 49f4476bd9SJan Schumann } 506c8c1f46SChristopher Smith 51*5aa905e9SAndreas Gohr $this->pregsplit_safe = version_compare(PCRE_VERSION, '6.7', '>='); 52f4476bd9SJan Schumann } 53f4476bd9SJan Schumann 54f4476bd9SJan Schumann /** 55311f4603SAndreas Gohr * Check user+password 56f4476bd9SJan Schumann * 57f4476bd9SJan Schumann * Checks if the given user exists and the given 58f4476bd9SJan Schumann * plaintext password is correct 59f4476bd9SJan Schumann * 60f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 61311f4603SAndreas Gohr * @param string $user 62311f4603SAndreas Gohr * @param string $pass 63f4476bd9SJan Schumann * @return bool 64f4476bd9SJan Schumann */ 65*5aa905e9SAndreas Gohr public function checkPass($user, $pass) 66*5aa905e9SAndreas Gohr { 67f4476bd9SJan Schumann $userinfo = $this->getUserData($user); 68f4476bd9SJan Schumann if ($userinfo === false) return false; 69f4476bd9SJan Schumann 70f4476bd9SJan Schumann return auth_verifyPassword($pass, $this->users[$user]['pass']); 71f4476bd9SJan Schumann } 72f4476bd9SJan Schumann 73f4476bd9SJan Schumann /** 74f4476bd9SJan Schumann * Return user info 75f4476bd9SJan Schumann * 76f4476bd9SJan Schumann * Returns info about the given user needs to contain 77f4476bd9SJan Schumann * at least these fields: 78f4476bd9SJan Schumann * 79f4476bd9SJan Schumann * name string full name of the user 80f4476bd9SJan Schumann * mail string email addres of the user 81f4476bd9SJan Schumann * grps array list of groups the user is in 82f4476bd9SJan Schumann * 83f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 84311f4603SAndreas Gohr * @param string $user 852046a654SChristopher Smith * @param bool $requireGroups (optional) ignored by this plugin, grps info always supplied 86253d4b48SGerrit Uitslag * @return array|false 87f4476bd9SJan Schumann */ 88*5aa905e9SAndreas Gohr public function getUserData($user, $requireGroups = true) 89*5aa905e9SAndreas Gohr { 90*5aa905e9SAndreas Gohr if ($this->users === null) $this->loadUserData(); 91f4476bd9SJan Schumann return isset($this->users[$user]) ? $this->users[$user] : false; 92f4476bd9SJan Schumann } 93f4476bd9SJan Schumann 94f4476bd9SJan Schumann /** 95f95ecbbfSAngus Gratton * Creates a string suitable for saving as a line 96f95ecbbfSAngus Gratton * in the file database 97f95ecbbfSAngus Gratton * (delimiters escaped, etc.) 98f95ecbbfSAngus Gratton * 99f95ecbbfSAngus Gratton * @param string $user 100f95ecbbfSAngus Gratton * @param string $pass 101f95ecbbfSAngus Gratton * @param string $name 102f95ecbbfSAngus Gratton * @param string $mail 103f95ecbbfSAngus Gratton * @param array $grps list of groups the user is in 104f95ecbbfSAngus Gratton * @return string 105f95ecbbfSAngus Gratton */ 106*5aa905e9SAndreas Gohr protected function createUserLine($user, $pass, $name, $mail, $grps) 107*5aa905e9SAndreas Gohr { 108f95ecbbfSAngus Gratton $groups = join(',', $grps); 109f95ecbbfSAngus Gratton $userline = array($user, $pass, $name, $mail, $groups); 110f95ecbbfSAngus Gratton $userline = str_replace('\\', '\\\\', $userline); // escape \ as \\ 111f95ecbbfSAngus Gratton $userline = str_replace(':', '\\:', $userline); // escape : as \: 112f95ecbbfSAngus Gratton $userline = join(':', $userline)."\n"; 113f95ecbbfSAngus Gratton return $userline; 114f95ecbbfSAngus Gratton } 115f95ecbbfSAngus Gratton 116f95ecbbfSAngus Gratton /** 117f4476bd9SJan Schumann * Create a new User 118f4476bd9SJan Schumann * 119f4476bd9SJan Schumann * Returns false if the user already exists, null when an error 120f4476bd9SJan Schumann * occurred and true if everything went well. 121f4476bd9SJan Schumann * 122f4476bd9SJan Schumann * The new user will be added to the default group by this 123f4476bd9SJan Schumann * function if grps are not specified (default behaviour). 124f4476bd9SJan Schumann * 125f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 126f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 127311f4603SAndreas Gohr * 128311f4603SAndreas Gohr * @param string $user 129311f4603SAndreas Gohr * @param string $pwd 130311f4603SAndreas Gohr * @param string $name 131311f4603SAndreas Gohr * @param string $mail 132311f4603SAndreas Gohr * @param array $grps 133311f4603SAndreas Gohr * @return bool|null|string 134f4476bd9SJan Schumann */ 135*5aa905e9SAndreas Gohr public function createUser($user, $pwd, $name, $mail, $grps = null) 136*5aa905e9SAndreas Gohr { 137f4476bd9SJan Schumann global $conf; 138f4476bd9SJan Schumann global $config_cascade; 139f4476bd9SJan Schumann 140f4476bd9SJan Schumann // user mustn't already exist 141db9faf02SPatrick Brown if ($this->getUserData($user) !== false) { 142db9faf02SPatrick Brown msg($this->getLang('userexists'), -1); 143db9faf02SPatrick Brown return false; 144db9faf02SPatrick Brown } 145f4476bd9SJan Schumann 146f4476bd9SJan Schumann $pass = auth_cryptPassword($pwd); 147f4476bd9SJan Schumann 148f4476bd9SJan Schumann // set default group if no groups specified 149f4476bd9SJan Schumann if (!is_array($grps)) $grps = array($conf['defaultgroup']); 150f4476bd9SJan Schumann 151f4476bd9SJan Schumann // prepare user line 152*5aa905e9SAndreas Gohr $userline = $this->createUserLine($user, $pass, $name, $mail, $grps); 153f4476bd9SJan Schumann 154db9faf02SPatrick Brown if (!io_saveFile($config_cascade['plainauth.users']['default'], $userline, true)) { 155db9faf02SPatrick Brown msg($this->getLang('writefail'), -1); 156db9faf02SPatrick Brown return null; 157f4476bd9SJan Schumann } 158f4476bd9SJan Schumann 159db9faf02SPatrick Brown $this->users[$user] = compact('pass', 'name', 'mail', 'grps'); 160db9faf02SPatrick Brown return $pwd; 161f4476bd9SJan Schumann } 162f4476bd9SJan Schumann 163f4476bd9SJan Schumann /** 164f4476bd9SJan Schumann * Modify user data 165f4476bd9SJan Schumann * 166f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 167311f4603SAndreas Gohr * @param string $user nick of the user to be changed 168311f4603SAndreas Gohr * @param array $changes array of field/value pairs to be changed (password will be clear text) 169f4476bd9SJan Schumann * @return bool 170f4476bd9SJan Schumann */ 171*5aa905e9SAndreas Gohr public function modifyUser($user, $changes) 172*5aa905e9SAndreas Gohr { 173f4476bd9SJan Schumann global $ACT; 174f4476bd9SJan Schumann global $config_cascade; 175f4476bd9SJan Schumann 176f4476bd9SJan Schumann // sanity checks, user must already exist and there must be something to change 177db9faf02SPatrick Brown if (($userinfo = $this->getUserData($user)) === false) { 178db9faf02SPatrick Brown msg($this->getLang('usernotexists'), -1); 179db9faf02SPatrick Brown return false; 180db9faf02SPatrick Brown } 18142cbd322SAndreas Gohr 18242cbd322SAndreas Gohr // don't modify protected users 18342cbd322SAndreas Gohr if (!empty($userinfo['protected'])) { 18442cbd322SAndreas Gohr msg(sprintf($this->getLang('protected'), hsc($user)), -1); 18542cbd322SAndreas Gohr return false; 18642cbd322SAndreas Gohr } 18742cbd322SAndreas Gohr 188f4476bd9SJan Schumann if (!is_array($changes) || !count($changes)) return true; 189f4476bd9SJan Schumann 190f4476bd9SJan Schumann // update userinfo with new data, remembering to encrypt any password 191f4476bd9SJan Schumann $newuser = $user; 192f4476bd9SJan Schumann foreach ($changes as $field => $value) { 193f4476bd9SJan Schumann if ($field == 'user') { 194f4476bd9SJan Schumann $newuser = $value; 195f4476bd9SJan Schumann continue; 196f4476bd9SJan Schumann } 197f4476bd9SJan Schumann if ($field == 'pass') $value = auth_cryptPassword($value); 198f4476bd9SJan Schumann $userinfo[$field] = $value; 199f4476bd9SJan Schumann } 200f4476bd9SJan Schumann 201*5aa905e9SAndreas Gohr $userline = $this->createUserLine( 20264159a61SAndreas Gohr $newuser, 20364159a61SAndreas Gohr $userinfo['pass'], 20464159a61SAndreas Gohr $userinfo['name'], 20564159a61SAndreas Gohr $userinfo['mail'], 20664159a61SAndreas Gohr $userinfo['grps'] 20764159a61SAndreas Gohr ); 208f4476bd9SJan Schumann 209699e3c49SPatrick Brown if (!io_replaceInFile($config_cascade['plainauth.users']['default'], '/^'.$user.':/', $userline, true)) { 210699e3c49SPatrick Brown msg('There was an error modifying your user data. You may need to register again.', -1); 211699e3c49SPatrick Brown // FIXME, io functions should be fail-safe so existing data isn't lost 212311f4603SAndreas Gohr $ACT = 'register'; 213f4476bd9SJan Schumann return false; 214f4476bd9SJan Schumann } 215f4476bd9SJan Schumann 216f4476bd9SJan Schumann $this->users[$newuser] = $userinfo; 217f4476bd9SJan Schumann return true; 218f4476bd9SJan Schumann } 219f4476bd9SJan Schumann 220f4476bd9SJan Schumann /** 221f4476bd9SJan Schumann * Remove one or more users from the list of registered users 222f4476bd9SJan Schumann * 223f4476bd9SJan Schumann * @author Christopher Smith <chris@jalakai.co.uk> 224f4476bd9SJan Schumann * @param array $users array of users to be deleted 225f4476bd9SJan Schumann * @return int the number of users deleted 226f4476bd9SJan Schumann */ 227*5aa905e9SAndreas Gohr public function deleteUsers($users) 228*5aa905e9SAndreas Gohr { 229f4476bd9SJan Schumann global $config_cascade; 230f4476bd9SJan Schumann 231f4476bd9SJan Schumann if (!is_array($users) || empty($users)) return 0; 232f4476bd9SJan Schumann 233*5aa905e9SAndreas Gohr if ($this->users === null) $this->loadUserData(); 234f4476bd9SJan Schumann 235f4476bd9SJan Schumann $deleted = array(); 236f4476bd9SJan Schumann foreach ($users as $user) { 23742cbd322SAndreas Gohr // don't delete protected users 23842cbd322SAndreas Gohr if (!empty($this->users[$user]['protected'])) { 23942cbd322SAndreas Gohr msg(sprintf($this->getLang('protected'), hsc($user)), -1); 24042cbd322SAndreas Gohr continue; 24142cbd322SAndreas Gohr } 242f4476bd9SJan Schumann if (isset($this->users[$user])) $deleted[] = preg_quote($user, '/'); 243f4476bd9SJan Schumann } 244f4476bd9SJan Schumann 245f4476bd9SJan Schumann if (empty($deleted)) return 0; 246f4476bd9SJan Schumann 247f4476bd9SJan Schumann $pattern = '/^('.join('|', $deleted).'):/'; 248db9faf02SPatrick Brown if (!io_deleteFromFile($config_cascade['plainauth.users']['default'], $pattern, true)) { 249db9faf02SPatrick Brown msg($this->getLang('writefail'), -1); 250db9faf02SPatrick Brown return 0; 251db9faf02SPatrick Brown } 252f4476bd9SJan Schumann 2539d24536dSAndreas Gohr // reload the user list and count the difference 254f4476bd9SJan Schumann $count = count($this->users); 255*5aa905e9SAndreas Gohr $this->loadUserData(); 256f4476bd9SJan Schumann $count -= count($this->users); 257f4476bd9SJan Schumann return $count; 258f4476bd9SJan Schumann } 259f4476bd9SJan Schumann 260f4476bd9SJan Schumann /** 261f4476bd9SJan Schumann * Return a count of the number of user which meet $filter criteria 262f4476bd9SJan Schumann * 263f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 264311f4603SAndreas Gohr * 265311f4603SAndreas Gohr * @param array $filter 266311f4603SAndreas Gohr * @return int 267f4476bd9SJan Schumann */ 268*5aa905e9SAndreas Gohr public function getUserCount($filter = array()) 269*5aa905e9SAndreas Gohr { 270f4476bd9SJan Schumann 271*5aa905e9SAndreas Gohr if ($this->users === null) $this->loadUserData(); 272f4476bd9SJan Schumann 273f4476bd9SJan Schumann if (!count($filter)) return count($this->users); 274f4476bd9SJan Schumann 275f4476bd9SJan Schumann $count = 0; 276*5aa905e9SAndreas Gohr $this->constructPattern($filter); 277f4476bd9SJan Schumann 278f4476bd9SJan Schumann foreach ($this->users as $user => $info) { 279*5aa905e9SAndreas Gohr $count += $this->filter($user, $info); 280f4476bd9SJan Schumann } 281f4476bd9SJan Schumann 282f4476bd9SJan Schumann return $count; 283f4476bd9SJan Schumann } 284f4476bd9SJan Schumann 285f4476bd9SJan Schumann /** 286f4476bd9SJan Schumann * Bulk retrieval of user data 287f4476bd9SJan Schumann * 288f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 289311f4603SAndreas Gohr * 290311f4603SAndreas Gohr * @param int $start index of first user to be returned 291311f4603SAndreas Gohr * @param int $limit max number of users to be returned 292311f4603SAndreas Gohr * @param array $filter array of field/pattern pairs 293311f4603SAndreas Gohr * @return array userinfo (refer getUserData for internal userinfo details) 294f4476bd9SJan Schumann */ 295*5aa905e9SAndreas Gohr public function retrieveUsers($start = 0, $limit = 0, $filter = array()) 296*5aa905e9SAndreas Gohr { 297f4476bd9SJan Schumann 298*5aa905e9SAndreas Gohr if ($this->users === null) $this->loadUserData(); 299f4476bd9SJan Schumann 300f4476bd9SJan Schumann ksort($this->users); 301f4476bd9SJan Schumann 302f4476bd9SJan Schumann $i = 0; 303f4476bd9SJan Schumann $count = 0; 304f4476bd9SJan Schumann $out = array(); 305*5aa905e9SAndreas Gohr $this->constructPattern($filter); 306f4476bd9SJan Schumann 307f4476bd9SJan Schumann foreach ($this->users as $user => $info) { 308*5aa905e9SAndreas Gohr if ($this->filter($user, $info)) { 309f4476bd9SJan Schumann if ($i >= $start) { 310f4476bd9SJan Schumann $out[$user] = $info; 311f4476bd9SJan Schumann $count++; 312f4476bd9SJan Schumann if (($limit > 0) && ($count >= $limit)) break; 313f4476bd9SJan Schumann } 314f4476bd9SJan Schumann $i++; 315f4476bd9SJan Schumann } 316f4476bd9SJan Schumann } 317f4476bd9SJan Schumann 318f4476bd9SJan Schumann return $out; 319f4476bd9SJan Schumann } 320f4476bd9SJan Schumann 321f4476bd9SJan Schumann /** 322f4476bd9SJan Schumann * Only valid pageid's (no namespaces) for usernames 323311f4603SAndreas Gohr * 324311f4603SAndreas Gohr * @param string $user 325311f4603SAndreas Gohr * @return string 326f4476bd9SJan Schumann */ 327*5aa905e9SAndreas Gohr public function cleanUser($user) 328*5aa905e9SAndreas Gohr { 329f4476bd9SJan Schumann global $conf; 330f4476bd9SJan Schumann return cleanID(str_replace(':', $conf['sepchar'], $user)); 331f4476bd9SJan Schumann } 332f4476bd9SJan Schumann 333f4476bd9SJan Schumann /** 334f4476bd9SJan Schumann * Only valid pageid's (no namespaces) for groupnames 335311f4603SAndreas Gohr * 336311f4603SAndreas Gohr * @param string $group 337311f4603SAndreas Gohr * @return string 338f4476bd9SJan Schumann */ 339*5aa905e9SAndreas Gohr public function cleanGroup($group) 340*5aa905e9SAndreas Gohr { 341f4476bd9SJan Schumann global $conf; 342f4476bd9SJan Schumann return cleanID(str_replace(':', $conf['sepchar'], $group)); 343f4476bd9SJan Schumann } 344f4476bd9SJan Schumann 345f4476bd9SJan Schumann /** 346f4476bd9SJan Schumann * Load all user data 347f4476bd9SJan Schumann * 348f4476bd9SJan Schumann * loads the user file into a datastructure 349f4476bd9SJan Schumann * 350f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 351f4476bd9SJan Schumann */ 352*5aa905e9SAndreas Gohr protected function loadUserData() 353*5aa905e9SAndreas Gohr { 354f4476bd9SJan Schumann global $config_cascade; 355f4476bd9SJan Schumann 356*5aa905e9SAndreas Gohr $this->users = $this->readUserFile($config_cascade['plainauth.users']['default']); 357f4476bd9SJan Schumann 35842cbd322SAndreas Gohr // support protected users 35942cbd322SAndreas Gohr if (!empty($config_cascade['plainauth.users']['protected'])) { 360*5aa905e9SAndreas Gohr $protected = $this->readUserFile($config_cascade['plainauth.users']['protected']); 36142cbd322SAndreas Gohr foreach (array_keys($protected) as $key) { 36242cbd322SAndreas Gohr $protected[$key]['protected'] = true; 36342cbd322SAndreas Gohr } 36442cbd322SAndreas Gohr $this->users = array_merge($this->users, $protected); 36542cbd322SAndreas Gohr } 36642cbd322SAndreas Gohr } 367f4476bd9SJan Schumann 36842cbd322SAndreas Gohr /** 36942cbd322SAndreas Gohr * Read user data from given file 37042cbd322SAndreas Gohr * 37142cbd322SAndreas Gohr * ignores non existing files 37242cbd322SAndreas Gohr * 37342cbd322SAndreas Gohr * @param string $file the file to load data from 37442cbd322SAndreas Gohr * @return array 37542cbd322SAndreas Gohr */ 376*5aa905e9SAndreas Gohr protected function readUserFile($file) 377*5aa905e9SAndreas Gohr { 37842cbd322SAndreas Gohr $users = array(); 37942cbd322SAndreas Gohr if (!file_exists($file)) return $users; 38042cbd322SAndreas Gohr 38142cbd322SAndreas Gohr $lines = file($file); 382f4476bd9SJan Schumann foreach ($lines as $line) { 383f4476bd9SJan Schumann $line = preg_replace('/#.*$/', '', $line); //ignore comments 384f4476bd9SJan Schumann $line = trim($line); 385f4476bd9SJan Schumann if (empty($line)) continue; 386f4476bd9SJan Schumann 387*5aa905e9SAndreas Gohr $row = $this->splitUserData($line); 388f95ecbbfSAngus Gratton $row = str_replace('\\:', ':', $row); 389f95ecbbfSAngus Gratton $row = str_replace('\\\\', '\\', $row); 390f95ecbbfSAngus Gratton 391f4476bd9SJan Schumann $groups = array_values(array_filter(explode(",", $row[4]))); 392f4476bd9SJan Schumann 39342cbd322SAndreas Gohr $users[$row[0]]['pass'] = $row[1]; 39442cbd322SAndreas Gohr $users[$row[0]]['name'] = urldecode($row[2]); 39542cbd322SAndreas Gohr $users[$row[0]]['mail'] = $row[3]; 39642cbd322SAndreas Gohr $users[$row[0]]['grps'] = $groups; 397f4476bd9SJan Schumann } 39842cbd322SAndreas Gohr return $users; 399f4476bd9SJan Schumann } 400f4476bd9SJan Schumann 401*5aa905e9SAndreas Gohr /** 402*5aa905e9SAndreas Gohr * Get the user line split into it's parts 403*5aa905e9SAndreas Gohr * 404*5aa905e9SAndreas Gohr * @param string $line 405*5aa905e9SAndreas Gohr * @return string[] 406*5aa905e9SAndreas Gohr */ 407*5aa905e9SAndreas Gohr protected function splitUserData($line) 408*5aa905e9SAndreas Gohr { 4096c8c1f46SChristopher Smith // due to a bug in PCRE 6.6, preg_split will fail with the regex we use here 4106c8c1f46SChristopher Smith // refer github issues 877 & 885 411*5aa905e9SAndreas Gohr if ($this->pregsplit_safe) { 4126c8c1f46SChristopher Smith return preg_split('/(?<![^\\\\]\\\\)\:/', $line, 5); // allow for : escaped as \: 4136c8c1f46SChristopher Smith } 4146c8c1f46SChristopher Smith 4156c8c1f46SChristopher Smith $row = array(); 4166c8c1f46SChristopher Smith $piece = ''; 4179d846ff4SChristopher Smith $len = strlen($line); 4189d846ff4SChristopher Smith for ($i=0; $i<$len; $i++) { 4196c8c1f46SChristopher Smith if ($line[$i]=='\\') { 4209d846ff4SChristopher Smith $piece .= $line[$i]; 4216c8c1f46SChristopher Smith $i++; 4229d846ff4SChristopher Smith if ($i>=$len) break; 4236c8c1f46SChristopher Smith } elseif ($line[$i]==':') { 4246c8c1f46SChristopher Smith $row[] = $piece; 4256c8c1f46SChristopher Smith $piece = ''; 4266c8c1f46SChristopher Smith continue; 4276c8c1f46SChristopher Smith } 4286c8c1f46SChristopher Smith $piece .= $line[$i]; 4296c8c1f46SChristopher Smith } 4306c8c1f46SChristopher Smith $row[] = $piece; 4316c8c1f46SChristopher Smith 4326c8c1f46SChristopher Smith return $row; 4336c8c1f46SChristopher Smith } 4346c8c1f46SChristopher Smith 435f4476bd9SJan Schumann /** 436311f4603SAndreas Gohr * return true if $user + $info match $filter criteria, false otherwise 437f4476bd9SJan Schumann * 438f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 439311f4603SAndreas Gohr * 440311f4603SAndreas Gohr * @param string $user User login 441311f4603SAndreas Gohr * @param array $info User's userinfo array 442311f4603SAndreas Gohr * @return bool 443f4476bd9SJan Schumann */ 444*5aa905e9SAndreas Gohr protected function filter($user, $info) 445*5aa905e9SAndreas Gohr { 446*5aa905e9SAndreas Gohr foreach ($this->pattern as $item => $pattern) { 447f4476bd9SJan Schumann if ($item == 'user') { 448311f4603SAndreas Gohr if (!preg_match($pattern, $user)) return false; 449f4476bd9SJan Schumann } elseif ($item == 'grps') { 450311f4603SAndreas Gohr if (!count(preg_grep($pattern, $info['grps']))) return false; 451f4476bd9SJan Schumann } else { 452311f4603SAndreas Gohr if (!preg_match($pattern, $info[$item])) return false; 453f4476bd9SJan Schumann } 454f4476bd9SJan Schumann } 455311f4603SAndreas Gohr return true; 456f4476bd9SJan Schumann } 457f4476bd9SJan Schumann 458311f4603SAndreas Gohr /** 459311f4603SAndreas Gohr * construct a filter pattern 460311f4603SAndreas Gohr * 461311f4603SAndreas Gohr * @param array $filter 462311f4603SAndreas Gohr */ 463*5aa905e9SAndreas Gohr protected function constructPattern($filter) 464*5aa905e9SAndreas Gohr { 465*5aa905e9SAndreas Gohr $this->pattern = array(); 466f4476bd9SJan Schumann foreach ($filter as $item => $pattern) { 467*5aa905e9SAndreas Gohr $this->pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters 468f4476bd9SJan Schumann } 469f4476bd9SJan Schumann } 470f4476bd9SJan Schumann} 471