1f4476bd9SJan Schumann<?php 2f4476bd9SJan Schumann// must be run within Dokuwiki 3f4476bd9SJan Schumannif(!defined('DOKU_INC')) die(); 4f4476bd9SJan Schumann 5f4476bd9SJan Schumann/** 6f4476bd9SJan Schumann * Plaintext authentication backend 7f4476bd9SJan Schumann * 8f4476bd9SJan Schumann * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 9f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 10f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 11f4476bd9SJan Schumann * @author Jan Schumann <js@schumann-it.com> 12f4476bd9SJan Schumann */ 1393a7873eSAndreas Gohrclass auth_plugin_authplain extends DokuWiki_Auth_Plugin { 14311f4603SAndreas Gohr /** @var array user cache */ 15311f4603SAndreas Gohr protected $users = null; 16311f4603SAndreas Gohr 17311f4603SAndreas Gohr /** @var array filter pattern */ 18311f4603SAndreas Gohr protected $_pattern = array(); 19f4476bd9SJan Schumann 206c8c1f46SChristopher Smith /** @var bool safe version of preg_split */ 216c8c1f46SChristopher Smith protected $_pregsplit_safe = false; 226c8c1f46SChristopher Smith 23f4476bd9SJan Schumann /** 24f4476bd9SJan Schumann * Constructor 25f4476bd9SJan Schumann * 26f4476bd9SJan Schumann * Carry out sanity checks to ensure the object is 27f4476bd9SJan Schumann * able to operate. Set capabilities. 28f4476bd9SJan Schumann * 29f4476bd9SJan Schumann * @author Christopher Smith <chris@jalakai.co.uk> 30f4476bd9SJan Schumann */ 31311f4603SAndreas Gohr public function __construct() { 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 516c8c1f46SChristopher Smith $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 */ 65311f4603SAndreas Gohr public function checkPass($user, $pass) { 66f4476bd9SJan Schumann $userinfo = $this->getUserData($user); 67f4476bd9SJan Schumann if($userinfo === false) return false; 68f4476bd9SJan Schumann 69f4476bd9SJan Schumann return auth_verifyPassword($pass, $this->users[$user]['pass']); 70f4476bd9SJan Schumann } 71f4476bd9SJan Schumann 72f4476bd9SJan Schumann /** 73f4476bd9SJan Schumann * Return user info 74f4476bd9SJan Schumann * 75f4476bd9SJan Schumann * Returns info about the given user needs to contain 76f4476bd9SJan Schumann * at least these fields: 77f4476bd9SJan Schumann * 78f4476bd9SJan Schumann * name string full name of the user 79f4476bd9SJan Schumann * mail string email addres of the user 80f4476bd9SJan Schumann * grps array list of groups the user is in 81f4476bd9SJan Schumann * 82f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 83311f4603SAndreas Gohr * @param string $user 842046a654SChristopher Smith * @param bool $requireGroups (optional) ignored by this plugin, grps info always supplied 85253d4b48SGerrit Uitslag * @return array|false 86f4476bd9SJan Schumann */ 872046a654SChristopher Smith public function getUserData($user, $requireGroups=true) { 88f4476bd9SJan Schumann if($this->users === null) $this->_loadUserData(); 89f4476bd9SJan Schumann return isset($this->users[$user]) ? $this->users[$user] : false; 90f4476bd9SJan Schumann } 91f4476bd9SJan Schumann 92f4476bd9SJan Schumann /** 93f95ecbbfSAngus Gratton * Creates a string suitable for saving as a line 94f95ecbbfSAngus Gratton * in the file database 95f95ecbbfSAngus Gratton * (delimiters escaped, etc.) 96f95ecbbfSAngus Gratton * 97f95ecbbfSAngus Gratton * @param string $user 98f95ecbbfSAngus Gratton * @param string $pass 99f95ecbbfSAngus Gratton * @param string $name 100f95ecbbfSAngus Gratton * @param string $mail 101f95ecbbfSAngus Gratton * @param array $grps list of groups the user is in 102f95ecbbfSAngus Gratton * @return string 103f95ecbbfSAngus Gratton */ 104f95ecbbfSAngus Gratton protected function _createUserLine($user, $pass, $name, $mail, $grps) { 105f95ecbbfSAngus Gratton $groups = join(',', $grps); 106f95ecbbfSAngus Gratton $userline = array($user, $pass, $name, $mail, $groups); 107f95ecbbfSAngus Gratton $userline = str_replace('\\', '\\\\', $userline); // escape \ as \\ 108f95ecbbfSAngus Gratton $userline = str_replace(':', '\\:', $userline); // escape : as \: 109f95ecbbfSAngus Gratton $userline = join(':', $userline)."\n"; 110f95ecbbfSAngus Gratton return $userline; 111f95ecbbfSAngus Gratton } 112f95ecbbfSAngus Gratton 113f95ecbbfSAngus Gratton /** 114f4476bd9SJan Schumann * Create a new User 115f4476bd9SJan Schumann * 116f4476bd9SJan Schumann * Returns false if the user already exists, null when an error 117f4476bd9SJan Schumann * occurred and true if everything went well. 118f4476bd9SJan Schumann * 119f4476bd9SJan Schumann * The new user will be added to the default group by this 120f4476bd9SJan Schumann * function if grps are not specified (default behaviour). 121f4476bd9SJan Schumann * 122f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 123f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 124311f4603SAndreas Gohr * 125311f4603SAndreas Gohr * @param string $user 126311f4603SAndreas Gohr * @param string $pwd 127311f4603SAndreas Gohr * @param string $name 128311f4603SAndreas Gohr * @param string $mail 129311f4603SAndreas Gohr * @param array $grps 130311f4603SAndreas Gohr * @return bool|null|string 131f4476bd9SJan Schumann */ 132311f4603SAndreas Gohr public function createUser($user, $pwd, $name, $mail, $grps = null) { 133f4476bd9SJan Schumann global $conf; 134f4476bd9SJan Schumann global $config_cascade; 135f4476bd9SJan Schumann 136f4476bd9SJan Schumann // user mustn't already exist 137*db9faf02SPatrick Brown if($this->getUserData($user) !== false) { 138*db9faf02SPatrick Brown msg($this->getLang('userexists'), -1); 139*db9faf02SPatrick Brown return false; 140*db9faf02SPatrick Brown } 141f4476bd9SJan Schumann 142f4476bd9SJan Schumann $pass = auth_cryptPassword($pwd); 143f4476bd9SJan Schumann 144f4476bd9SJan Schumann // set default group if no groups specified 145f4476bd9SJan Schumann if(!is_array($grps)) $grps = array($conf['defaultgroup']); 146f4476bd9SJan Schumann 147f4476bd9SJan Schumann // prepare user line 148f95ecbbfSAngus Gratton $userline = $this->_createUserLine($user, $pass, $name, $mail, $grps); 149f4476bd9SJan Schumann 150*db9faf02SPatrick Brown if(!io_saveFile($config_cascade['plainauth.users']['default'], $userline, true)) { 151*db9faf02SPatrick Brown msg($this->getLang('writefail'), -1); 152*db9faf02SPatrick Brown return null; 153f4476bd9SJan Schumann } 154f4476bd9SJan Schumann 155*db9faf02SPatrick Brown $this->users[$user] = compact('pass', 'name', 'mail', 'grps'); 156*db9faf02SPatrick Brown return $pwd; 157f4476bd9SJan Schumann } 158f4476bd9SJan Schumann 159f4476bd9SJan Schumann /** 160f4476bd9SJan Schumann * Modify user data 161f4476bd9SJan Schumann * 162f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 163311f4603SAndreas Gohr * @param string $user nick of the user to be changed 164311f4603SAndreas Gohr * @param array $changes array of field/value pairs to be changed (password will be clear text) 165f4476bd9SJan Schumann * @return bool 166f4476bd9SJan Schumann */ 167311f4603SAndreas Gohr public function modifyUser($user, $changes) { 168f4476bd9SJan Schumann global $ACT; 169f4476bd9SJan Schumann global $config_cascade; 170f4476bd9SJan Schumann 171f4476bd9SJan Schumann // sanity checks, user must already exist and there must be something to change 172*db9faf02SPatrick Brown if(($userinfo = $this->getUserData($user)) === false) { 173*db9faf02SPatrick Brown msg($this->getLang('usernotexists'), -1); 174*db9faf02SPatrick Brown return false; 175*db9faf02SPatrick Brown } 176f4476bd9SJan Schumann if(!is_array($changes) || !count($changes)) return true; 177f4476bd9SJan Schumann 178f4476bd9SJan Schumann // update userinfo with new data, remembering to encrypt any password 179f4476bd9SJan Schumann $newuser = $user; 180f4476bd9SJan Schumann foreach($changes as $field => $value) { 181f4476bd9SJan Schumann if($field == 'user') { 182f4476bd9SJan Schumann $newuser = $value; 183f4476bd9SJan Schumann continue; 184f4476bd9SJan Schumann } 185f4476bd9SJan Schumann if($field == 'pass') $value = auth_cryptPassword($value); 186f4476bd9SJan Schumann $userinfo[$field] = $value; 187f4476bd9SJan Schumann } 188f4476bd9SJan Schumann 189f95ecbbfSAngus Gratton $userline = $this->_createUserLine($newuser, $userinfo['pass'], $userinfo['name'], $userinfo['mail'], $userinfo['grps']); 190f4476bd9SJan Schumann 191f4476bd9SJan Schumann if(!$this->deleteUsers(array($user))) { 192*db9faf02SPatrick Brown msg($this->getLang('writefail'), -1); 193f4476bd9SJan Schumann return false; 194f4476bd9SJan Schumann } 195f4476bd9SJan Schumann 196f4476bd9SJan Schumann if(!io_saveFile($config_cascade['plainauth.users']['default'], $userline, true)) { 197f4476bd9SJan Schumann msg('There was an error modifying your user data. You should register again.', -1); 198f4476bd9SJan Schumann // FIXME, user has been deleted but not recreated, should force a logout and redirect to login page 199*db9faf02SPatrick Brown // Should replace the delete/save hybrid modify with an atomic io_replaceInFile 200311f4603SAndreas Gohr $ACT = 'register'; 201f4476bd9SJan Schumann return false; 202f4476bd9SJan Schumann } 203f4476bd9SJan Schumann 204f4476bd9SJan Schumann $this->users[$newuser] = $userinfo; 205f4476bd9SJan Schumann return true; 206f4476bd9SJan Schumann } 207f4476bd9SJan Schumann 208f4476bd9SJan Schumann /** 209f4476bd9SJan Schumann * Remove one or more users from the list of registered users 210f4476bd9SJan Schumann * 211f4476bd9SJan Schumann * @author Christopher Smith <chris@jalakai.co.uk> 212f4476bd9SJan Schumann * @param array $users array of users to be deleted 213f4476bd9SJan Schumann * @return int the number of users deleted 214f4476bd9SJan Schumann */ 215311f4603SAndreas Gohr public function deleteUsers($users) { 216f4476bd9SJan Schumann global $config_cascade; 217f4476bd9SJan Schumann 218f4476bd9SJan Schumann if(!is_array($users) || empty($users)) return 0; 219f4476bd9SJan Schumann 220f4476bd9SJan Schumann if($this->users === null) $this->_loadUserData(); 221f4476bd9SJan Schumann 222f4476bd9SJan Schumann $deleted = array(); 223f4476bd9SJan Schumann foreach($users as $user) { 224f4476bd9SJan Schumann if(isset($this->users[$user])) $deleted[] = preg_quote($user, '/'); 225f4476bd9SJan Schumann } 226f4476bd9SJan Schumann 227f4476bd9SJan Schumann if(empty($deleted)) return 0; 228f4476bd9SJan Schumann 229f4476bd9SJan Schumann $pattern = '/^('.join('|', $deleted).'):/'; 230*db9faf02SPatrick Brown if (!io_deleteFromFile($config_cascade['plainauth.users']['default'], $pattern, true)) { 231*db9faf02SPatrick Brown msg($this->getLang('writefail'), -1); 232*db9faf02SPatrick Brown return 0; 233*db9faf02SPatrick Brown } 234f4476bd9SJan Schumann 2359d24536dSAndreas Gohr // reload the user list and count the difference 236f4476bd9SJan Schumann $count = count($this->users); 237f4476bd9SJan Schumann $this->_loadUserData(); 238f4476bd9SJan Schumann $count -= count($this->users); 239f4476bd9SJan Schumann return $count; 240f4476bd9SJan Schumann } 241f4476bd9SJan Schumann 242f4476bd9SJan Schumann /** 243f4476bd9SJan Schumann * Return a count of the number of user which meet $filter criteria 244f4476bd9SJan Schumann * 245f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 246311f4603SAndreas Gohr * 247311f4603SAndreas Gohr * @param array $filter 248311f4603SAndreas Gohr * @return int 249f4476bd9SJan Schumann */ 250311f4603SAndreas Gohr public function getUserCount($filter = array()) { 251f4476bd9SJan Schumann 252f4476bd9SJan Schumann if($this->users === null) $this->_loadUserData(); 253f4476bd9SJan Schumann 254f4476bd9SJan Schumann if(!count($filter)) return count($this->users); 255f4476bd9SJan Schumann 256f4476bd9SJan Schumann $count = 0; 257f4476bd9SJan Schumann $this->_constructPattern($filter); 258f4476bd9SJan Schumann 259f4476bd9SJan Schumann foreach($this->users as $user => $info) { 260f4476bd9SJan Schumann $count += $this->_filter($user, $info); 261f4476bd9SJan Schumann } 262f4476bd9SJan Schumann 263f4476bd9SJan Schumann return $count; 264f4476bd9SJan Schumann } 265f4476bd9SJan Schumann 266f4476bd9SJan Schumann /** 267f4476bd9SJan Schumann * Bulk retrieval of user data 268f4476bd9SJan Schumann * 269f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 270311f4603SAndreas Gohr * 271311f4603SAndreas Gohr * @param int $start index of first user to be returned 272311f4603SAndreas Gohr * @param int $limit max number of users to be returned 273311f4603SAndreas Gohr * @param array $filter array of field/pattern pairs 274311f4603SAndreas Gohr * @return array userinfo (refer getUserData for internal userinfo details) 275f4476bd9SJan Schumann */ 276311f4603SAndreas Gohr public function retrieveUsers($start = 0, $limit = 0, $filter = array()) { 277f4476bd9SJan Schumann 278f4476bd9SJan Schumann if($this->users === null) $this->_loadUserData(); 279f4476bd9SJan Schumann 280f4476bd9SJan Schumann ksort($this->users); 281f4476bd9SJan Schumann 282f4476bd9SJan Schumann $i = 0; 283f4476bd9SJan Schumann $count = 0; 284f4476bd9SJan Schumann $out = array(); 285f4476bd9SJan Schumann $this->_constructPattern($filter); 286f4476bd9SJan Schumann 287f4476bd9SJan Schumann foreach($this->users as $user => $info) { 288f4476bd9SJan Schumann if($this->_filter($user, $info)) { 289f4476bd9SJan Schumann if($i >= $start) { 290f4476bd9SJan Schumann $out[$user] = $info; 291f4476bd9SJan Schumann $count++; 292f4476bd9SJan Schumann if(($limit > 0) && ($count >= $limit)) break; 293f4476bd9SJan Schumann } 294f4476bd9SJan Schumann $i++; 295f4476bd9SJan Schumann } 296f4476bd9SJan Schumann } 297f4476bd9SJan Schumann 298f4476bd9SJan Schumann return $out; 299f4476bd9SJan Schumann } 300f4476bd9SJan Schumann 301f4476bd9SJan Schumann /** 302f4476bd9SJan Schumann * Only valid pageid's (no namespaces) for usernames 303311f4603SAndreas Gohr * 304311f4603SAndreas Gohr * @param string $user 305311f4603SAndreas Gohr * @return string 306f4476bd9SJan Schumann */ 307311f4603SAndreas Gohr public function cleanUser($user) { 308f4476bd9SJan Schumann global $conf; 309f4476bd9SJan Schumann return cleanID(str_replace(':', $conf['sepchar'], $user)); 310f4476bd9SJan Schumann } 311f4476bd9SJan Schumann 312f4476bd9SJan Schumann /** 313f4476bd9SJan Schumann * Only valid pageid's (no namespaces) for groupnames 314311f4603SAndreas Gohr * 315311f4603SAndreas Gohr * @param string $group 316311f4603SAndreas Gohr * @return string 317f4476bd9SJan Schumann */ 318311f4603SAndreas Gohr public function cleanGroup($group) { 319f4476bd9SJan Schumann global $conf; 320f4476bd9SJan Schumann return cleanID(str_replace(':', $conf['sepchar'], $group)); 321f4476bd9SJan Schumann } 322f4476bd9SJan Schumann 323f4476bd9SJan Schumann /** 324f4476bd9SJan Schumann * Load all user data 325f4476bd9SJan Schumann * 326f4476bd9SJan Schumann * loads the user file into a datastructure 327f4476bd9SJan Schumann * 328f4476bd9SJan Schumann * @author Andreas Gohr <andi@splitbrain.org> 329f4476bd9SJan Schumann */ 330311f4603SAndreas Gohr protected function _loadUserData() { 331f4476bd9SJan Schumann global $config_cascade; 332f4476bd9SJan Schumann 333f4476bd9SJan Schumann $this->users = array(); 334f4476bd9SJan Schumann 33579e79377SAndreas Gohr if(!file_exists($config_cascade['plainauth.users']['default'])) return; 336f4476bd9SJan Schumann 337f4476bd9SJan Schumann $lines = file($config_cascade['plainauth.users']['default']); 338f4476bd9SJan Schumann foreach($lines as $line) { 339f4476bd9SJan Schumann $line = preg_replace('/#.*$/', '', $line); //ignore comments 340f4476bd9SJan Schumann $line = trim($line); 341f4476bd9SJan Schumann if(empty($line)) continue; 342f4476bd9SJan Schumann 343f95ecbbfSAngus Gratton /* NB: preg_split can be deprecated/replaced with str_getcsv once dokuwiki is min php 5.3 */ 3446c8c1f46SChristopher Smith $row = $this->_splitUserData($line); 345f95ecbbfSAngus Gratton $row = str_replace('\\:', ':', $row); 346f95ecbbfSAngus Gratton $row = str_replace('\\\\', '\\', $row); 347f95ecbbfSAngus Gratton 348f4476bd9SJan Schumann $groups = array_values(array_filter(explode(",", $row[4]))); 349f4476bd9SJan Schumann 350f4476bd9SJan Schumann $this->users[$row[0]]['pass'] = $row[1]; 351f4476bd9SJan Schumann $this->users[$row[0]]['name'] = urldecode($row[2]); 352f4476bd9SJan Schumann $this->users[$row[0]]['mail'] = $row[3]; 353f4476bd9SJan Schumann $this->users[$row[0]]['grps'] = $groups; 354f4476bd9SJan Schumann } 355f4476bd9SJan Schumann } 356f4476bd9SJan Schumann 3576c8c1f46SChristopher Smith protected function _splitUserData($line){ 3586c8c1f46SChristopher Smith // due to a bug in PCRE 6.6, preg_split will fail with the regex we use here 3596c8c1f46SChristopher Smith // refer github issues 877 & 885 3606c8c1f46SChristopher Smith if ($this->_pregsplit_safe){ 3616c8c1f46SChristopher Smith return preg_split('/(?<![^\\\\]\\\\)\:/', $line, 5); // allow for : escaped as \: 3626c8c1f46SChristopher Smith } 3636c8c1f46SChristopher Smith 3646c8c1f46SChristopher Smith $row = array(); 3656c8c1f46SChristopher Smith $piece = ''; 3669d846ff4SChristopher Smith $len = strlen($line); 3679d846ff4SChristopher Smith for($i=0; $i<$len; $i++){ 3686c8c1f46SChristopher Smith if ($line[$i]=='\\'){ 3699d846ff4SChristopher Smith $piece .= $line[$i]; 3706c8c1f46SChristopher Smith $i++; 3719d846ff4SChristopher Smith if ($i>=$len) break; 3726c8c1f46SChristopher Smith } else if ($line[$i]==':'){ 3736c8c1f46SChristopher Smith $row[] = $piece; 3746c8c1f46SChristopher Smith $piece = ''; 3756c8c1f46SChristopher Smith continue; 3766c8c1f46SChristopher Smith } 3776c8c1f46SChristopher Smith $piece .= $line[$i]; 3786c8c1f46SChristopher Smith } 3796c8c1f46SChristopher Smith $row[] = $piece; 3806c8c1f46SChristopher Smith 3816c8c1f46SChristopher Smith return $row; 3826c8c1f46SChristopher Smith } 3836c8c1f46SChristopher Smith 384f4476bd9SJan Schumann /** 385311f4603SAndreas Gohr * return true if $user + $info match $filter criteria, false otherwise 386f4476bd9SJan Schumann * 387f4476bd9SJan Schumann * @author Chris Smith <chris@jalakai.co.uk> 388311f4603SAndreas Gohr * 389311f4603SAndreas Gohr * @param string $user User login 390311f4603SAndreas Gohr * @param array $info User's userinfo array 391311f4603SAndreas Gohr * @return bool 392f4476bd9SJan Schumann */ 393311f4603SAndreas Gohr protected function _filter($user, $info) { 394f4476bd9SJan Schumann foreach($this->_pattern as $item => $pattern) { 395f4476bd9SJan Schumann if($item == 'user') { 396311f4603SAndreas Gohr if(!preg_match($pattern, $user)) return false; 397f4476bd9SJan Schumann } else if($item == 'grps') { 398311f4603SAndreas Gohr if(!count(preg_grep($pattern, $info['grps']))) return false; 399f4476bd9SJan Schumann } else { 400311f4603SAndreas Gohr if(!preg_match($pattern, $info[$item])) return false; 401f4476bd9SJan Schumann } 402f4476bd9SJan Schumann } 403311f4603SAndreas Gohr return true; 404f4476bd9SJan Schumann } 405f4476bd9SJan Schumann 406311f4603SAndreas Gohr /** 407311f4603SAndreas Gohr * construct a filter pattern 408311f4603SAndreas Gohr * 409311f4603SAndreas Gohr * @param array $filter 410311f4603SAndreas Gohr */ 411311f4603SAndreas Gohr protected function _constructPattern($filter) { 412f4476bd9SJan Schumann $this->_pattern = array(); 413f4476bd9SJan Schumann foreach($filter as $item => $pattern) { 414f4476bd9SJan Schumann $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters 415f4476bd9SJan Schumann } 416f4476bd9SJan Schumann } 417f4476bd9SJan Schumann} 418