149f2871cSAndreas Gohr<?php 21da41c8bSAndreas Gohr 31da41c8bSAndreas Gohruse dokuwiki\Extension\AdminPlugin; 41da41c8bSAndreas Gohruse dokuwiki\Form\Form; 5655fe6c1SAndreas Gohruse dokuwiki\Utf8\PhpString; 6*c609f1dcSAndreas Gohruse splitbrain\phpico\PhpIco; 71da41c8bSAndreas Gohruse splitbrain\RingIcon\RingIcon; 81da41c8bSAndreas Gohr 949f2871cSAndreas Gohr/** 1049f2871cSAndreas Gohr * DokuWiki Plugin farmer (Admin Component) 1149f2871cSAndreas Gohr * 121da41c8bSAndreas Gohr * Create new animals 131da41c8bSAndreas Gohr * 1449f2871cSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 1549f2871cSAndreas Gohr * @author Michael Große <grosse@cosmocode.de> 1649f2871cSAndreas Gohr */ 171da41c8bSAndreas Gohrclass admin_plugin_farmer_new extends AdminPlugin 181da41c8bSAndreas Gohr{ 1949f2871cSAndreas Gohr /** @var helper_plugin_farmer $helper */ 2049f2871cSAndreas Gohr protected $helper; 2149f2871cSAndreas Gohr 2249f2871cSAndreas Gohr /** 2349f2871cSAndreas Gohr * admin_plugin_farmer_new constructor. 2449f2871cSAndreas Gohr */ 251da41c8bSAndreas Gohr public function __construct() 261da41c8bSAndreas Gohr { 2749f2871cSAndreas Gohr $this->helper = plugin_load('helper', 'farmer'); 2849f2871cSAndreas Gohr } 2949f2871cSAndreas Gohr 30341a2d35SAndreas Gohr /** @inheritdoc */ 31341a2d35SAndreas Gohr public function showInMenu() 32341a2d35SAndreas Gohr { 33341a2d35SAndreas Gohr return false; 34341a2d35SAndreas Gohr } 35341a2d35SAndreas Gohr 3649f2871cSAndreas Gohr /** 3749f2871cSAndreas Gohr * Should carry out any processing required by the plugin. 3849f2871cSAndreas Gohr */ 391da41c8bSAndreas Gohr public function handle() 401da41c8bSAndreas Gohr { 4149f2871cSAndreas Gohr global $INPUT; 4249f2871cSAndreas Gohr global $ID; 4349f2871cSAndreas Gohr if (!$INPUT->has('farmer__submit')) return; 4449f2871cSAndreas Gohr 4549f2871cSAndreas Gohr $data = $this->validateAnimalData(); 4649f2871cSAndreas Gohr if (!$data) return; 471da41c8bSAndreas Gohr if ( 481da41c8bSAndreas Gohr $this->createNewAnimal( 491da41c8bSAndreas Gohr $data['name'], 501da41c8bSAndreas Gohr $data['admin'], 511da41c8bSAndreas Gohr $data['pass'], 521da41c8bSAndreas Gohr $data['template'], 531da41c8bSAndreas Gohr $data['aclpolicy'], 541da41c8bSAndreas Gohr $data['allowreg'] 551da41c8bSAndreas Gohr ) 561da41c8bSAndreas Gohr ) { 570336ab2aSAndreas Gohr $url = $this->helper->getAnimalURL($data['name']); 580336ab2aSAndreas Gohr $link = '<a href="' . $url . '">' . hsc($data['name']) . '</a>'; 590336ab2aSAndreas Gohr 600336ab2aSAndreas Gohr msg(sprintf($this->getLang('animal creation success'), $link), 1); 611da41c8bSAndreas Gohr $link = wl($ID, ['do' => 'admin', 'page' => 'farmer', 'sub' => 'new'], true, '&'); 6249f2871cSAndreas Gohr send_redirect($link); 6349f2871cSAndreas Gohr } 6449f2871cSAndreas Gohr } 6549f2871cSAndreas Gohr 6649f2871cSAndreas Gohr /** 6749f2871cSAndreas Gohr * Render HTML output, e.g. helpful text and a form 6849f2871cSAndreas Gohr */ 691da41c8bSAndreas Gohr public function html() 701da41c8bSAndreas Gohr { 716348ab5bSMichael Grosse global $lang; 721272da0cSAndreas Gohr $farmconfig = $this->helper->getConfig(); 7349f2871cSAndreas Gohr 741da41c8bSAndreas Gohr $form = new Form(); 7549f2871cSAndreas Gohr $form->addClass('plugin_farmer')->id('farmer__create_animal_form'); 7649f2871cSAndreas Gohr 7749f2871cSAndreas Gohr $form->addFieldsetOpen($this->getLang('animal configuration')); 7823164e01SAndreas Gohr $form->addTextInput('animalname', $this->getLang('animal')); 7949f2871cSAndreas Gohr $form->addFieldsetClose(); 8049f2871cSAndreas Gohr 81801ebaa1SAndreas Gohr $animals = $this->helper->getAllAnimals(); 82801ebaa1SAndreas Gohr array_unshift($animals, ''); 83801ebaa1SAndreas Gohr $form->addFieldsetOpen($this->getLang('animal template')); 841da41c8bSAndreas Gohr $form->addDropdown('animaltemplate', $animals) 851da41c8bSAndreas Gohr ->addClass('farmer_chosen_animals'); 86801ebaa1SAndreas Gohr $form->addFieldsetClose(); 87801ebaa1SAndreas Gohr 886348ab5bSMichael Grosse $form->addFieldsetOpen($lang['i_policy'])->attr('id', 'aclPolicyFieldset'); 891da41c8bSAndreas Gohr $policyOptions = ['open' => $lang['i_pol0'], 'public' => $lang['i_pol1'], 'closed' => $lang['i_pol2']]; 901da41c8bSAndreas Gohr $form->addDropdown('aclpolicy', $policyOptions) 911da41c8bSAndreas Gohr ->addClass('acl_chosen'); 926348ab5bSMichael Grosse if ($farmconfig['inherit']['main']) { 931da41c8bSAndreas Gohr $form->addRadioButton('allowreg', $this->getLang('inherit user registration')) 941da41c8bSAndreas Gohr ->val('inherit') 951da41c8bSAndreas Gohr ->attr('checked', 'checked'); 961da41c8bSAndreas Gohr $form->addRadioButton('allowreg', $this->getLang('enable user registration')) 971da41c8bSAndreas Gohr ->val('allow'); 981da41c8bSAndreas Gohr $form->addRadioButton('allowreg', $this->getLang('disable user registration')) 991da41c8bSAndreas Gohr ->val('disable'); 1006348ab5bSMichael Grosse } else { 1011da41c8bSAndreas Gohr $form->addCheckbox('allowreg', $lang['i_allowreg']) 1021da41c8bSAndreas Gohr ->attr('checked', 'checked'); 1036348ab5bSMichael Grosse } 1046348ab5bSMichael Grosse 1056348ab5bSMichael Grosse $form->addFieldsetClose(); 1066348ab5bSMichael Grosse 10749f2871cSAndreas Gohr $form->addFieldsetOpen($this->getLang('animal administrator')); 1081da41c8bSAndreas Gohr 1091da41c8bSAndreas Gohr $btn = $form->addRadioButton('adminsetup', $this->getLang('noUsers')) 1101da41c8bSAndreas Gohr ->val('noUsers'); 1111272da0cSAndreas Gohr if ($farmconfig['inherit']['users']) { 1121272da0cSAndreas Gohr $btn->attr('checked', 'checked'); // default when inherit available 1131a130845SAndreas Gohr } else { 1141a130845SAndreas Gohr // no user copying when inheriting 1151da41c8bSAndreas Gohr $form->addRadioButton('adminsetup', $this->getLang('importUsers')) 1161da41c8bSAndreas Gohr ->val('importUsers'); 1171da41c8bSAndreas Gohr $form->addRadioButton('adminsetup', $this->getLang('currentAdmin')) 1181da41c8bSAndreas Gohr ->val('currentAdmin'); 1191a130845SAndreas Gohr } 1201da41c8bSAndreas Gohr $btn = $form->addRadioButton('adminsetup', $this->getLang('newAdmin')) 1211da41c8bSAndreas Gohr ->val('newAdmin'); 1221272da0cSAndreas Gohr if (!$farmconfig['inherit']['users']) { 1231272da0cSAndreas Gohr $btn->attr('checked', 'checked'); // default when inherit not available 1241272da0cSAndreas Gohr } 12549f2871cSAndreas Gohr $form->addPasswordInput('adminPassword', $this->getLang('admin password')); 12649f2871cSAndreas Gohr $form->addFieldsetClose(); 12749f2871cSAndreas Gohr 1281da41c8bSAndreas Gohr $form->addButton('farmer__submit', $this->getLang('submit')) 1291da41c8bSAndreas Gohr ->attr('type', 'submit') 1301da41c8bSAndreas Gohr ->val('newAnimal'); 13149f2871cSAndreas Gohr echo $form->toHTML(); 13249f2871cSAndreas Gohr } 13349f2871cSAndreas Gohr 13449f2871cSAndreas Gohr /** 13549f2871cSAndreas Gohr * Validate the data for a new animal 13649f2871cSAndreas Gohr * 13749f2871cSAndreas Gohr * @return array|bool false on errors, clean data otherwise 13849f2871cSAndreas Gohr */ 1391da41c8bSAndreas Gohr protected function validateAnimalData() 1401da41c8bSAndreas Gohr { 14149f2871cSAndreas Gohr global $INPUT; 14249f2871cSAndreas Gohr 143655fe6c1SAndreas Gohr $animalname = $INPUT->filter('trim')->filter([PhpString::class, 'strtolower'])->str('animalname'); 14449f2871cSAndreas Gohr $adminsetup = $INPUT->str('adminsetup'); 14549f2871cSAndreas Gohr $adminpass = $INPUT->filter('trim')->str('adminPassword'); 146801ebaa1SAndreas Gohr $template = $INPUT->filter('trim')->str('animaltemplate'); 1476348ab5bSMichael Grosse $aclpolicy = $INPUT->filter('trim')->str('aclpolicy'); 1486348ab5bSMichael Grosse $allowreg = $INPUT->str('allowreg'); 14949f2871cSAndreas Gohr 1501da41c8bSAndreas Gohr $errors = []; 15149f2871cSAndreas Gohr 15249f2871cSAndreas Gohr if ($animalname === '') { 15349f2871cSAndreas Gohr $errors[] = $this->getLang('animalname_missing'); 15449f2871cSAndreas Gohr } elseif (!$this->helper->validateAnimalName($animalname)) { 15549f2871cSAndreas Gohr $errors[] = $this->getLang('animalname_invalid'); 15649f2871cSAndreas Gohr } 15749f2871cSAndreas Gohr 15849f2871cSAndreas Gohr if ($adminsetup === 'newAdmin' && $adminpass === '') { 15949f2871cSAndreas Gohr $errors[] = $this->getLang('adminPassword_empty'); 16049f2871cSAndreas Gohr } 16149f2871cSAndreas Gohr 16249f2871cSAndreas Gohr if ($animalname !== '' && file_exists(DOKU_FARMDIR . '/' . $animalname)) { 16349f2871cSAndreas Gohr $errors[] = $this->getLang('animalname_preexisting'); 16449f2871cSAndreas Gohr } 16549f2871cSAndreas Gohr 1661da41c8bSAndreas Gohr if (!is_dir(DOKU_FARMDIR . $template) && !in_array($aclpolicy, ['open', 'public', 'closed'])) { 1676348ab5bSMichael Grosse $errors[] = $this->getLang('aclpolicy missing/bad'); 1686348ab5bSMichael Grosse } 1696348ab5bSMichael Grosse 17049f2871cSAndreas Gohr if ($errors) { 17149f2871cSAndreas Gohr foreach ($errors as $error) { 17249f2871cSAndreas Gohr msg($error, -1); 17349f2871cSAndreas Gohr } 17449f2871cSAndreas Gohr return false; 17549f2871cSAndreas Gohr } 17649f2871cSAndreas Gohr 1778262a4cbSAndreas Gohr if (!is_dir(DOKU_FARMDIR . $template)) { 178801ebaa1SAndreas Gohr $template = ''; 179801ebaa1SAndreas Gohr } 1806348ab5bSMichael Grosse if ($template != '') { 1816348ab5bSMichael Grosse $aclpolicy = ''; 1826348ab5bSMichael Grosse } 183801ebaa1SAndreas Gohr 1841da41c8bSAndreas Gohr return [ 18549f2871cSAndreas Gohr 'name' => $animalname, 18649f2871cSAndreas Gohr 'admin' => $adminsetup, 187801ebaa1SAndreas Gohr 'pass' => $adminpass, 1886348ab5bSMichael Grosse 'template' => $template, 1896348ab5bSMichael Grosse 'aclpolicy' => $aclpolicy, 1906348ab5bSMichael Grosse 'allowreg' => $allowreg 1911da41c8bSAndreas Gohr ]; 19249f2871cSAndreas Gohr } 19349f2871cSAndreas Gohr 19449f2871cSAndreas Gohr /** 19549f2871cSAndreas Gohr * Create a new animal 19649f2871cSAndreas Gohr * 19749f2871cSAndreas Gohr * @param string $name name/title of the animal, will be the directory name for htaccess setup 19849f2871cSAndreas Gohr * @param string $adminSetup newAdmin, currentAdmin or importUsers 19949f2871cSAndreas Gohr * @param string $adminPassword required if $adminSetup is newAdmin 200801ebaa1SAndreas Gohr * @param string $template name of animal to copy 2016348ab5bSMichael Grosse * @param $aclpolicy 2026348ab5bSMichael Grosse * @param $userreg 20349f2871cSAndreas Gohr * @return bool true if successful 2046348ab5bSMichael Grosse * @throws Exception 20549f2871cSAndreas Gohr */ 2061da41c8bSAndreas Gohr protected function createNewAnimal($name, $adminSetup, $adminPassword, $template, $aclpolicy, $userreg) 2071da41c8bSAndreas Gohr { 2088262a4cbSAndreas Gohr $animaldir = DOKU_FARMDIR . $name; 20949f2871cSAndreas Gohr 21049f2871cSAndreas Gohr // copy basic template 2111da41c8bSAndreas Gohr $ok = $this->helper->copyDir(__DIR__ . '/../_animal', $animaldir); 21249f2871cSAndreas Gohr if (!$ok) { 21349f2871cSAndreas Gohr msg($this->getLang('animal creation error'), -1); 21449f2871cSAndreas Gohr return false; 21549f2871cSAndreas Gohr } 21649f2871cSAndreas Gohr 217801ebaa1SAndreas Gohr // copy animal template 218801ebaa1SAndreas Gohr if ($template != '') { 2191da41c8bSAndreas Gohr foreach (['conf', 'data/pages', 'data/media', 'data/meta', 'data/media_meta', 'index'] as $dir) { 2208262a4cbSAndreas Gohr $templatedir = DOKU_FARMDIR . $template . '/' . $dir; 221801ebaa1SAndreas Gohr if (!is_dir($templatedir)) continue; 222801ebaa1SAndreas Gohr // do not copy changelogs in meta 223f64a85f7SAndreas Gohr if (str_ends_with($dir, 'meta')) { 224801ebaa1SAndreas Gohr $exclude = '/\.changes$/'; 225801ebaa1SAndreas Gohr } else { 226801ebaa1SAndreas Gohr $exclude = ''; 227801ebaa1SAndreas Gohr } 2281da41c8bSAndreas Gohr if (!$this->helper->copyDir($templatedir, $animaldir . '/' . $dir, $exclude)) { 229801ebaa1SAndreas Gohr msg(sprintf($this->getLang('animal template copy error'), $dir), -1); 230801ebaa1SAndreas Gohr // we go on anyway 231801ebaa1SAndreas Gohr } 232801ebaa1SAndreas Gohr } 233801ebaa1SAndreas Gohr } 234801ebaa1SAndreas Gohr 23549f2871cSAndreas Gohr // append title to local config 23649f2871cSAndreas Gohr $ok &= io_saveFile($animaldir . '/conf/local.php', "\n" . '$conf[\'title\'] = \'' . $name . '\';' . "\n", true); 23749f2871cSAndreas Gohr 2384eba53bcSAndreas Gohr try { 239b263debeSAndreas Gohr if (function_exists('imagecreatetruecolor')) { 240c3bd7eb3SAndreas Gohr $logo = $animaldir . '/data/media/wiki/logo.png'; 241c3bd7eb3SAndreas Gohr if (!file_exists($logo)) { 2421da41c8bSAndreas Gohr $ringicon = new RingIcon(64); 243c3bd7eb3SAndreas Gohr $ringicon->createImage($animaldir, $logo); 244c3bd7eb3SAndreas Gohr } 245c3bd7eb3SAndreas Gohr 246c3bd7eb3SAndreas Gohr $icon = $animaldir . '/data/media/wiki/favicon.ico'; 247c3bd7eb3SAndreas Gohr if (!file_exists($icon)) { 248*c609f1dcSAndreas Gohr $icongen = new PhpIco($logo); 2491da41c8bSAndreas Gohr $icongen->saveIco($icon); 250c3bd7eb3SAndreas Gohr } 251b263debeSAndreas Gohr } 2524eba53bcSAndreas Gohr } catch (\Exception $ignore) { 2534eba53bcSAndreas Gohr // something went wrong, but we don't care. this is a nice to have feature only 2544eba53bcSAndreas Gohr } 25549f2871cSAndreas Gohr 25649f2871cSAndreas Gohr // create admin user 25749f2871cSAndreas Gohr if ($adminSetup === 'newAdmin') { 25849f2871cSAndreas Gohr $users = "# <?php exit()?>\n" . $this->makeAdminLine($adminPassword) . "\n"; 25949f2871cSAndreas Gohr } elseif ($adminSetup === 'currentAdmin') { 26049f2871cSAndreas Gohr $users = "# <?php exit()?>\n" . $this->getAdminLine() . "\n"; 2611272da0cSAndreas Gohr } elseif ($adminSetup === 'noUsers') { 262801ebaa1SAndreas Gohr if (file_exists($animaldir . '/conf/users.auth.php')) { 263801ebaa1SAndreas Gohr // a user file exists already, probably from animal template - don't overwrite 264801ebaa1SAndreas Gohr $users = ''; 265801ebaa1SAndreas Gohr } else { 266801ebaa1SAndreas Gohr // create empty user file 2671272da0cSAndreas Gohr $users = "# <?php exit()?>\n"; 268801ebaa1SAndreas Gohr } 26949f2871cSAndreas Gohr } else { 27049f2871cSAndreas Gohr $users = io_readFile(DOKU_CONF . 'users.auth.php'); 27149f2871cSAndreas Gohr } 272801ebaa1SAndreas Gohr if ($users) { 27349f2871cSAndreas Gohr $ok &= io_saveFile($animaldir . '/conf/users.auth.php', $users); 274801ebaa1SAndreas Gohr } 27549f2871cSAndreas Gohr 2766348ab5bSMichael Grosse if ($aclpolicy != '') { 2776348ab5bSMichael Grosse $aclfile = file($animaldir . '/conf/acl.auth.php'); 2782b85f30dSAndreas Gohr $aclfile = array_map('trim', $aclfile); 2796348ab5bSMichael Grosse array_pop($aclfile); 2806348ab5bSMichael Grosse switch ($aclpolicy) { 2816348ab5bSMichael Grosse case 'open': 2826348ab5bSMichael Grosse $aclfile[] = "* @ALL 8"; 2836348ab5bSMichael Grosse break; 2846348ab5bSMichael Grosse case 'public': 2856348ab5bSMichael Grosse $aclfile[] = "* @ALL 1"; 2866348ab5bSMichael Grosse $aclfile[] = "* @user 8"; 2876348ab5bSMichael Grosse break; 2886348ab5bSMichael Grosse case 'closed': 2896348ab5bSMichael Grosse $aclfile[] = "* @ALL 0"; 2906348ab5bSMichael Grosse $aclfile[] = "* @user 8"; 2916348ab5bSMichael Grosse break; 2926348ab5bSMichael Grosse default: 2936348ab5bSMichael Grosse throw new Exception('Undefined aclpolicy given'); 2946348ab5bSMichael Grosse } 2951da41c8bSAndreas Gohr $ok &= io_saveFile($animaldir . '/conf/acl.auth.php', implode("\n", $aclfile) . "\n"); 2966348ab5bSMichael Grosse 2976348ab5bSMichael Grosse global $conf; 2986348ab5bSMichael Grosse switch ($userreg) { 2996348ab5bSMichael Grosse case 'allow': 3001da41c8bSAndreas Gohr $disableactions = implode(',', array_diff(explode(',', $conf['disableactions']), ['register'])); 3011da41c8bSAndreas Gohr $ok &= io_saveFile( 3021da41c8bSAndreas Gohr $animaldir . '/conf/local.php', 3031da41c8bSAndreas Gohr "\n" . '$conf[\'disableactions\'] = \'' . $disableactions . '\';' . "\n", 3041da41c8bSAndreas Gohr true 3051da41c8bSAndreas Gohr ); 3066348ab5bSMichael Grosse break; 3076348ab5bSMichael Grosse case 'disable': 3081da41c8bSAndreas Gohr $disableactions = implode(',', array_merge(explode(',', $conf['disableactions']), ['register'])); 3091da41c8bSAndreas Gohr $ok &= io_saveFile( 3101da41c8bSAndreas Gohr $animaldir . '/conf/local.php', 3111da41c8bSAndreas Gohr "\n" . '$conf[\'disableactions\'] = \'' . $disableactions . '\';' . "\n", 3121da41c8bSAndreas Gohr true 3131da41c8bSAndreas Gohr ); 3146348ab5bSMichael Grosse break; 3156348ab5bSMichael Grosse case 'inherit': 3166348ab5bSMichael Grosse case true: 3176348ab5bSMichael Grosse // nothing needs to be done 3186348ab5bSMichael Grosse break; 3196348ab5bSMichael Grosse default: 3201da41c8bSAndreas Gohr $ok &= io_saveFile( 3211da41c8bSAndreas Gohr $animaldir . '/conf/local.php', 3221da41c8bSAndreas Gohr "\n" . '$conf[\'disableactions\'] = \'register\';' . "\n", 3231da41c8bSAndreas Gohr true 3241da41c8bSAndreas Gohr ); 3256348ab5bSMichael Grosse } 3266348ab5bSMichael Grosse } 3276348ab5bSMichael Grosse 3284664a1d2SAndreas Gohr // deactivate plugins by default FIXME this should be nicer 32949f2871cSAndreas Gohr $deactivatedPluginsList = explode(',', $this->getConf('deactivated plugins')); 3304664a1d2SAndreas Gohr $deactivatedPluginsList = array_map('trim', $deactivatedPluginsList); 3314664a1d2SAndreas Gohr $deactivatedPluginsList = array_unique($deactivatedPluginsList); 3324664a1d2SAndreas Gohr $deactivatedPluginsList = array_filter($deactivatedPluginsList); 33349f2871cSAndreas Gohr foreach ($deactivatedPluginsList as $plugin) { 334af1c6dd8SAndreas Gohr $this->helper->setPluginState(trim($plugin), $name, 0); 33549f2871cSAndreas Gohr } 33649f2871cSAndreas Gohr 33749f2871cSAndreas Gohr return $ok; 33849f2871cSAndreas Gohr } 33949f2871cSAndreas Gohr 34049f2871cSAndreas Gohr /** 34149f2871cSAndreas Gohr * Creates a new user line 34249f2871cSAndreas Gohr * 34349f2871cSAndreas Gohr * @param $password 34449f2871cSAndreas Gohr * @return string 34549f2871cSAndreas Gohr */ 3461da41c8bSAndreas Gohr protected function makeAdminLine($password) 3471da41c8bSAndreas Gohr { 34849f2871cSAndreas Gohr $pass = auth_cryptPassword($password); 3491da41c8bSAndreas Gohr $line = implode( 3501da41c8bSAndreas Gohr ':', 3511da41c8bSAndreas Gohr ['admin', $pass, 'Administrator', 'admin@example.org', 'admin,user'] 3521272da0cSAndreas Gohr ); 35349f2871cSAndreas Gohr return $line; 35449f2871cSAndreas Gohr } 35549f2871cSAndreas Gohr 35649f2871cSAndreas Gohr /** 35749f2871cSAndreas Gohr * Copies the current user as new admin line 35849f2871cSAndreas Gohr * 35949f2871cSAndreas Gohr * @return string 36049f2871cSAndreas Gohr */ 3611da41c8bSAndreas Gohr protected function getAdminLine() 3621da41c8bSAndreas Gohr { 36349f2871cSAndreas Gohr $currentAdmin = $_SERVER['REMOTE_USER']; 36449f2871cSAndreas Gohr $masterUsers = file_get_contents(DOKU_CONF . 'users.auth.php'); 36549f2871cSAndreas Gohr $masterUsers = ltrim(strstr($masterUsers, "\n" . $currentAdmin . ":")); 3661da41c8bSAndreas Gohr 36749f2871cSAndreas Gohr $newAdmin = substr($masterUsers, 0, strpos($masterUsers, "\n") + 1); 36849f2871cSAndreas Gohr return $newAdmin; 36949f2871cSAndreas Gohr } 37049f2871cSAndreas Gohr} 371