10440ff15Schris<?php 2*54cc7aa4SAndreas Gohr 3*54cc7aa4SAndreas Gohruse dokuwiki\Utf8\Clean; 40440ff15Schris/* 50440ff15Schris * User Manager 60440ff15Schris * 70440ff15Schris * Dokuwiki Admin Plugin 80440ff15Schris * 90440ff15Schris * This version of the user manager has been modified to only work with 100440ff15Schris * objectified version of auth system 110440ff15Schris * 120440ff15Schris * @author neolao <neolao@neolao.com> 130440ff15Schris * @author Chris Smith <chris@jalakai.co.uk> 140440ff15Schris */ 150440ff15Schris/** 160440ff15Schris * All DokuWiki plugins to extend the admin function 170440ff15Schris * need to inherit from this class 180440ff15Schris */ 193a97d936SAndreas Gohrclass admin_plugin_usermanager extends DokuWiki_Admin_Plugin 203a97d936SAndreas Gohr{ 213a97d936SAndreas Gohr const IMAGE_DIR = DOKU_BASE.'lib/plugins/usermanager/images/'; 220440ff15Schris 23*54cc7aa4SAndreas Gohr protected $auth; // auth object 243a97d936SAndreas Gohr protected $users_total = 0; // number of registered users 25*54cc7aa4SAndreas Gohr protected $filter = []; // user selection filter(s) 263a97d936SAndreas Gohr protected $start = 0; // index of first user to be displayed 273a97d936SAndreas Gohr protected $last = 0; // index of the last user to be displayed 283a97d936SAndreas Gohr protected $pagesize = 20; // number of users to list on one page 293a97d936SAndreas Gohr protected $edit_user = ''; // set to user selected for editing 30*54cc7aa4SAndreas Gohr protected $edit_userdata = []; 313a97d936SAndreas Gohr protected $disabled = ''; // if disabled set to explanatory string 32*54cc7aa4SAndreas Gohr protected $import_failures = []; 333a97d936SAndreas Gohr protected $lastdisabled = false; // set to true if last user is unknown and last button is hence buggy 340440ff15Schris 350440ff15Schris /** 360440ff15Schris * Constructor 370440ff15Schris */ 383a97d936SAndreas Gohr public function __construct() 393a97d936SAndreas Gohr { 40c5a7c0c6SGerrit Uitslag /** @var DokuWiki_Auth_Plugin $auth */ 410440ff15Schris global $auth; 420440ff15Schris 430440ff15Schris $this->setupLocale(); 4451d94d49Schris 4551d94d49Schris if (!isset($auth)) { 463a97d936SAndreas Gohr $this->disabled = $this->lang['noauth']; 4782fd59b6SAndreas Gohr } elseif (!$auth->canDo('getUsers')) { 483a97d936SAndreas Gohr $this->disabled = $this->lang['nosupport']; 4951d94d49Schris } else { 5051d94d49Schris // we're good to go 513a97d936SAndreas Gohr $this->auth = & $auth; 5251d94d49Schris } 53ae1afd2fSChristopher Smith 54ae1afd2fSChristopher Smith // attempt to retrieve any import failures from the session 550e80bb5eSChristopher Smith if (!empty($_SESSION['import_failures'])) { 563a97d936SAndreas Gohr $this->import_failures = $_SESSION['import_failures']; 57ae1afd2fSChristopher Smith } 580440ff15Schris } 590440ff15Schris 600440ff15Schris /** 61c5a7c0c6SGerrit Uitslag * Return prompt for admin menu 62253d4b48SGerrit Uitslag * 63253d4b48SGerrit Uitslag * @param string $language 64253d4b48SGerrit Uitslag * @return string 650440ff15Schris */ 663a97d936SAndreas Gohr public function getMenuText($language) 673a97d936SAndreas Gohr { 680440ff15Schris 693a97d936SAndreas Gohr if (!is_null($this->auth)) 700440ff15Schris return parent::getMenuText($language); 710440ff15Schris 723a97d936SAndreas Gohr return $this->getLang('menu').' '.$this->disabled; 730440ff15Schris } 740440ff15Schris 750440ff15Schris /** 760440ff15Schris * return sort order for position in admin menu 77253d4b48SGerrit Uitslag * 78253d4b48SGerrit Uitslag * @return int 790440ff15Schris */ 803a97d936SAndreas Gohr public function getMenuSort() 813a97d936SAndreas Gohr { 820440ff15Schris return 2; 830440ff15Schris } 840440ff15Schris 850440ff15Schris /** 8667a31a83SMichael Große * @return int current start value for pageination 8767a31a83SMichael Große */ 883a97d936SAndreas Gohr public function getStart() 893a97d936SAndreas Gohr { 903a97d936SAndreas Gohr return $this->start; 9167a31a83SMichael Große } 9267a31a83SMichael Große 9367a31a83SMichael Große /** 9467a31a83SMichael Große * @return int number of users per page 9567a31a83SMichael Große */ 963a97d936SAndreas Gohr public function getPagesize() 973a97d936SAndreas Gohr { 983a97d936SAndreas Gohr return $this->pagesize; 9967a31a83SMichael Große } 10067a31a83SMichael Große 10167a31a83SMichael Große /** 102462e9e37SMichael Große * @param boolean $lastdisabled 103462e9e37SMichael Große */ 1043a97d936SAndreas Gohr public function setLastdisabled($lastdisabled) 1053a97d936SAndreas Gohr { 1063a97d936SAndreas Gohr $this->lastdisabled = $lastdisabled; 107462e9e37SMichael Große } 108462e9e37SMichael Große 109462e9e37SMichael Große /** 110c5a7c0c6SGerrit Uitslag * Handle user request 111253d4b48SGerrit Uitslag * 112253d4b48SGerrit Uitslag * @return bool 1130440ff15Schris */ 1143a97d936SAndreas Gohr public function handle() 1153a97d936SAndreas Gohr { 11600d58927SMichael Hamann global $INPUT; 1173a97d936SAndreas Gohr if (is_null($this->auth)) return false; 1180440ff15Schris 1190440ff15Schris // extract the command and any specific parameters 1200440ff15Schris // submit button name is of the form - fn[cmd][param(s)] 12100d58927SMichael Hamann $fn = $INPUT->param('fn'); 1220440ff15Schris 1230440ff15Schris if (is_array($fn)) { 1240440ff15Schris $cmd = key($fn); 1250440ff15Schris $param = is_array($fn[$cmd]) ? key($fn[$cmd]) : null; 1260440ff15Schris } else { 1270440ff15Schris $cmd = $fn; 1280440ff15Schris $param = null; 1290440ff15Schris } 1300440ff15Schris 1310440ff15Schris if ($cmd != "search") { 1323a97d936SAndreas Gohr $this->start = $INPUT->int('start', 0); 1333a97d936SAndreas Gohr $this->filter = $this->retrieveFilter(); 1340440ff15Schris } 1350440ff15Schris 1360440ff15Schris switch ($cmd) { 1373a97d936SAndreas Gohr case "add": 1383a97d936SAndreas Gohr $this->addUser(); 1390440ff15Schris break; 1403a97d936SAndreas Gohr case "delete": 1413a97d936SAndreas Gohr $this->deleteUser(); 1423a97d936SAndreas Gohr break; 1433a97d936SAndreas Gohr case "modify": 1443a97d936SAndreas Gohr $this->modifyUser(); 1453a97d936SAndreas Gohr break; 1463a97d936SAndreas Gohr case "edit": 1473a97d936SAndreas Gohr $this->editUser($param); 1483a97d936SAndreas Gohr break; 1493a97d936SAndreas Gohr case "search": 1503a97d936SAndreas Gohr $this->setFilter($param); 1513a97d936SAndreas Gohr $this->start = 0; 1523a97d936SAndreas Gohr break; 1533a97d936SAndreas Gohr case "export": 1543a97d936SAndreas Gohr $this->exportCSV(); 1553a97d936SAndreas Gohr break; 1563a97d936SAndreas Gohr case "import": 1573a97d936SAndreas Gohr $this->importCSV(); 1583a97d936SAndreas Gohr break; 1593a97d936SAndreas Gohr case "importfails": 1603a97d936SAndreas Gohr $this->downloadImportFailures(); 1613a97d936SAndreas Gohr break; 1620440ff15Schris } 1630440ff15Schris 1643a97d936SAndreas Gohr $this->users_total = $this->auth->canDo('getUserCount') ? $this->auth->getUserCount($this->filter) : -1; 1650440ff15Schris 1660440ff15Schris // page handling 1670440ff15Schris switch ($cmd) { 1683a97d936SAndreas Gohr case 'start': 1693a97d936SAndreas Gohr $this->start = 0; 1703a97d936SAndreas Gohr break; 1713a97d936SAndreas Gohr case 'prev': 1723a97d936SAndreas Gohr $this->start -= $this->pagesize; 1733a97d936SAndreas Gohr break; 1743a97d936SAndreas Gohr case 'next': 1753a97d936SAndreas Gohr $this->start += $this->pagesize; 1763a97d936SAndreas Gohr break; 1773a97d936SAndreas Gohr case 'last': 1783a97d936SAndreas Gohr $this->start = $this->users_total; 1793a97d936SAndreas Gohr break; 1800440ff15Schris } 1813a97d936SAndreas Gohr $this->validatePagination(); 182c5a7c0c6SGerrit Uitslag return true; 1830440ff15Schris } 1840440ff15Schris 1850440ff15Schris /** 186c5a7c0c6SGerrit Uitslag * Output appropriate html 187253d4b48SGerrit Uitslag * 188253d4b48SGerrit Uitslag * @return bool 1890440ff15Schris */ 1903a97d936SAndreas Gohr public function html() 1913a97d936SAndreas Gohr { 1920440ff15Schris global $ID; 1930440ff15Schris 1943a97d936SAndreas Gohr if (is_null($this->auth)) { 1950440ff15Schris print $this->lang['badauth']; 1960440ff15Schris return false; 1970440ff15Schris } 1980440ff15Schris 1993a97d936SAndreas Gohr $user_list = $this->auth->retrieveUsers($this->start, $this->pagesize, $this->filter); 2000440ff15Schris 2013a97d936SAndreas Gohr $page_buttons = $this->pagination(); 2023a97d936SAndreas Gohr $delete_disable = $this->auth->canDo('delUser') ? '' : 'disabled="disabled"'; 2030440ff15Schris 2043a97d936SAndreas Gohr $editable = $this->auth->canDo('UserMod'); 2053a97d936SAndreas Gohr $export_label = empty($this->filter) ? $this->lang['export_all'] : $this->lang['export_filtered']; 2066154103cSmatthiasgrimm 2070440ff15Schris print $this->locale_xhtml('intro'); 2080440ff15Schris print $this->locale_xhtml('list'); 2090440ff15Schris 21058dde80dSAnika Henke ptln("<div id=\"user__manager\">"); 21158dde80dSAnika Henke ptln("<div class=\"level2\">"); 2120440ff15Schris 2133a97d936SAndreas Gohr if ($this->users_total > 0) { 21464159a61SAndreas Gohr ptln( 21564159a61SAndreas Gohr "<p>" . sprintf( 21664159a61SAndreas Gohr $this->lang['summary'], 2173a97d936SAndreas Gohr $this->start + 1, 2183a97d936SAndreas Gohr $this->last, 2193a97d936SAndreas Gohr $this->users_total, 2203a97d936SAndreas Gohr $this->auth->getUserCount() 22164159a61SAndreas Gohr ) . "</p>" 22264159a61SAndreas Gohr ); 2230440ff15Schris } else { 2243a97d936SAndreas Gohr if ($this->users_total < 0) { 225a102b175SGerrit Uitslag $allUserTotal = 0; 226a102b175SGerrit Uitslag } else { 2273a97d936SAndreas Gohr $allUserTotal = $this->auth->getUserCount(); 228a102b175SGerrit Uitslag } 229a102b175SGerrit Uitslag ptln("<p>".sprintf($this->lang['nonefound'], $allUserTotal)."</p>"); 2300440ff15Schris } 2310440ff15Schris ptln("<form action=\"".wl($ID)."\" method=\"post\">"); 232634d7150SAndreas Gohr formSecurityToken(); 233c7b28ffdSAnika Henke ptln(" <div class=\"table\">"); 2340440ff15Schris ptln(" <table class=\"inline\">"); 2350440ff15Schris ptln(" <thead>"); 2360440ff15Schris ptln(" <tr>"); 23764159a61SAndreas Gohr ptln(" <th> </th> 23864159a61SAndreas Gohr <th>".$this->lang["user_id"]."</th> 23964159a61SAndreas Gohr <th>".$this->lang["user_name"]."</th> 24064159a61SAndreas Gohr <th>".$this->lang["user_mail"]."</th> 24164159a61SAndreas Gohr <th>".$this->lang["user_groups"]."</th>"); 2420440ff15Schris ptln(" </tr>"); 2430440ff15Schris 2440440ff15Schris ptln(" <tr>"); 24564159a61SAndreas Gohr ptln(" <td class=\"rightalign\"><input type=\"image\" src=\"". 2463a97d936SAndreas Gohr self::IMAGE_DIR."search.png\" name=\"fn[search][new]\" title=\"". 24764159a61SAndreas Gohr $this->lang['search_prompt']."\" alt=\"".$this->lang['search']."\" class=\"button\" /></td>"); 24864159a61SAndreas Gohr ptln(" <td><input type=\"text\" name=\"userid\" class=\"edit\" value=\"". 2493a97d936SAndreas Gohr $this->htmlFilter('user')."\" /></td>"); 25064159a61SAndreas Gohr ptln(" <td><input type=\"text\" name=\"username\" class=\"edit\" value=\"". 2513a97d936SAndreas Gohr $this->htmlFilter('name')."\" /></td>"); 25264159a61SAndreas Gohr ptln(" <td><input type=\"text\" name=\"usermail\" class=\"edit\" value=\"". 2533a97d936SAndreas Gohr $this->htmlFilter('mail')."\" /></td>"); 25464159a61SAndreas Gohr ptln(" <td><input type=\"text\" name=\"usergroups\" class=\"edit\" value=\"". 2553a97d936SAndreas Gohr $this->htmlFilter('grps')."\" /></td>"); 2560440ff15Schris ptln(" </tr>"); 2570440ff15Schris ptln(" </thead>"); 2580440ff15Schris 2593a97d936SAndreas Gohr if ($this->users_total) { 2600440ff15Schris ptln(" <tbody>"); 2610440ff15Schris foreach ($user_list as $user => $userinfo) { 2620440ff15Schris extract($userinfo); 263c5a7c0c6SGerrit Uitslag /** 264c5a7c0c6SGerrit Uitslag * @var string $name 265c5a7c0c6SGerrit Uitslag * @var string $pass 266c5a7c0c6SGerrit Uitslag * @var string $mail 267c5a7c0c6SGerrit Uitslag * @var array $grps 268c5a7c0c6SGerrit Uitslag */ 269*54cc7aa4SAndreas Gohr $groups = implode(', ', $grps); 270a2c0246eSAnika Henke ptln(" <tr class=\"user_info\">"); 27164159a61SAndreas Gohr ptln(" <td class=\"centeralign\"><input type=\"checkbox\" name=\"delete[".hsc($user). 27264159a61SAndreas Gohr "]\" ".$delete_disable." /></td>"); 2732365d73dSAnika Henke if ($editable) { 274*54cc7aa4SAndreas Gohr ptln(" <td><a href=\"".wl($ID, ['fn[edit]['.$user.']' => 1, 27577d19185SAndreas Gohr 'do' => 'admin', 27677d19185SAndreas Gohr 'page' => 'usermanager', 277*54cc7aa4SAndreas Gohr 'sectok' => getSecurityToken()]). 27877d19185SAndreas Gohr "\" title=\"".$this->lang['edit_prompt']."\">".hsc($user)."</a></td>"); 2792365d73dSAnika Henke } else { 2802365d73dSAnika Henke ptln(" <td>".hsc($user)."</td>"); 2812365d73dSAnika Henke } 2822365d73dSAnika Henke ptln(" <td>".hsc($name)."</td><td>".hsc($mail)."</td><td>".hsc($groups)."</td>"); 2830440ff15Schris ptln(" </tr>"); 2840440ff15Schris } 2850440ff15Schris ptln(" </tbody>"); 2860440ff15Schris } 2870440ff15Schris 2880440ff15Schris ptln(" <tbody>"); 2892365d73dSAnika Henke ptln(" <tr><td colspan=\"5\" class=\"centeralign\">"); 290a2c0246eSAnika Henke ptln(" <span class=\"medialeft\">"); 29164159a61SAndreas Gohr ptln(" <button type=\"submit\" name=\"fn[delete]\" id=\"usrmgr__del\" ".$delete_disable.">". 29264159a61SAndreas Gohr $this->lang['delete_selected']."</button>"); 29376c49356SMike Wilmes ptln(" </span>"); 29476c49356SMike Wilmes ptln(" <span class=\"mediaright\">"); 29564159a61SAndreas Gohr ptln(" <button type=\"submit\" name=\"fn[start]\" ".$page_buttons['start'].">". 29664159a61SAndreas Gohr $this->lang['start']."</button>"); 29764159a61SAndreas Gohr ptln(" <button type=\"submit\" name=\"fn[prev]\" ".$page_buttons['prev'].">". 29864159a61SAndreas Gohr $this->lang['prev']."</button>"); 29964159a61SAndreas Gohr ptln(" <button type=\"submit\" name=\"fn[next]\" ".$page_buttons['next'].">". 30064159a61SAndreas Gohr $this->lang['next']."</button>"); 30164159a61SAndreas Gohr ptln(" <button type=\"submit\" name=\"fn[last]\" ".$page_buttons['last'].">". 30264159a61SAndreas Gohr $this->lang['last']."</button>"); 30376c49356SMike Wilmes ptln(" </span>"); 3043a97d936SAndreas Gohr if (!empty($this->filter)) { 305ae614416SAnika Henke ptln(" <button type=\"submit\" name=\"fn[search][clear]\">".$this->lang['clear']."</button>"); 3065c967d3dSChristopher Smith } 307ae614416SAnika Henke ptln(" <button type=\"submit\" name=\"fn[export]\">".$export_label."</button>"); 3085164d9c9SAnika Henke ptln(" <input type=\"hidden\" name=\"do\" value=\"admin\" />"); 3095164d9c9SAnika Henke ptln(" <input type=\"hidden\" name=\"page\" value=\"usermanager\" />"); 310daf4ca4eSAnika Henke 3113a97d936SAndreas Gohr $this->htmlFilterSettings(2); 312daf4ca4eSAnika Henke 3130440ff15Schris ptln(" </td></tr>"); 3140440ff15Schris ptln(" </tbody>"); 3150440ff15Schris ptln(" </table>"); 316c7b28ffdSAnika Henke ptln(" </div>"); 3170440ff15Schris 3180440ff15Schris ptln("</form>"); 3190440ff15Schris ptln("</div>"); 3200440ff15Schris 3213a97d936SAndreas Gohr $style = $this->edit_user ? " class=\"edit_user\"" : ""; 3220440ff15Schris 3233a97d936SAndreas Gohr if ($this->auth->canDo('addUser')) { 3240440ff15Schris ptln("<div".$style.">"); 3250440ff15Schris print $this->locale_xhtml('add'); 3260440ff15Schris ptln(" <div class=\"level2\">"); 3270440ff15Schris 328*54cc7aa4SAndreas Gohr $this->htmlUserForm('add', null, [], 4); 3290440ff15Schris 3300440ff15Schris ptln(" </div>"); 3310440ff15Schris ptln("</div>"); 3320440ff15Schris } 3330440ff15Schris 3343a97d936SAndreas Gohr if ($this->edit_user && $this->auth->canDo('UserMod')) { 335c632fc69SAndreas Gohr ptln("<div".$style." id=\"scroll__here\">"); 3360440ff15Schris print $this->locale_xhtml('edit'); 3370440ff15Schris ptln(" <div class=\"level2\">"); 3380440ff15Schris 3393a97d936SAndreas Gohr $this->htmlUserForm('modify', $this->edit_user, $this->edit_userdata, 4); 3400440ff15Schris 3410440ff15Schris ptln(" </div>"); 3420440ff15Schris ptln("</div>"); 3430440ff15Schris } 344ae1afd2fSChristopher Smith 3453a97d936SAndreas Gohr if ($this->auth->canDo('addUser')) { 3463a97d936SAndreas Gohr $this->htmlImportForm(); 347ae1afd2fSChristopher Smith } 34858dde80dSAnika Henke ptln("</div>"); 349c5a7c0c6SGerrit Uitslag return true; 3500440ff15Schris } 3510440ff15Schris 35282fd59b6SAndreas Gohr /** 35364cdf779SAndreas Gohr * User Manager is only available if the auth backend supports it 35464cdf779SAndreas Gohr * 35564cdf779SAndreas Gohr * @inheritdoc 35664cdf779SAndreas Gohr * @return bool 35764cdf779SAndreas Gohr */ 35864cdf779SAndreas Gohr public function isAccessibleByCurrentUser() 35964cdf779SAndreas Gohr { 36064cdf779SAndreas Gohr /** @var DokuWiki_Auth_Plugin $auth */ 36164cdf779SAndreas Gohr global $auth; 36264cdf779SAndreas Gohr if(!$auth || !$auth->canDo('getUsers') ) { 36364cdf779SAndreas Gohr return false; 36464cdf779SAndreas Gohr } 36564cdf779SAndreas Gohr 36664cdf779SAndreas Gohr return parent::isAccessibleByCurrentUser(); 36764cdf779SAndreas Gohr } 36864cdf779SAndreas Gohr 36964cdf779SAndreas Gohr 37064cdf779SAndreas Gohr /** 371c5a7c0c6SGerrit Uitslag * Display form to add or modify a user 372c5a7c0c6SGerrit Uitslag * 373c5a7c0c6SGerrit Uitslag * @param string $cmd 'add' or 'modify' 374c5a7c0c6SGerrit Uitslag * @param string $user id of user 375c5a7c0c6SGerrit Uitslag * @param array $userdata array with name, mail, pass and grps 376c5a7c0c6SGerrit Uitslag * @param int $indent 37782fd59b6SAndreas Gohr */ 378*54cc7aa4SAndreas Gohr protected function htmlUserForm($cmd, $user = '', $userdata = [], $indent = 0) 3793a97d936SAndreas Gohr { 380a6858c6aSchris global $conf; 381bb4866bdSchris global $ID; 382be9008d3SChristopher Smith global $lang; 383*54cc7aa4SAndreas Gohr $name = ''; 384*54cc7aa4SAndreas Gohr $mail = ''; 385*54cc7aa4SAndreas Gohr $groups = ''; 386*54cc7aa4SAndreas Gohr $notes = []; 3870440ff15Schris 3880440ff15Schris if ($user) { 38978c7c8c9Schris extract($userdata); 390*54cc7aa4SAndreas Gohr if (!empty($grps)) $groups = implode(',', $grps); 391a6858c6aSchris } else { 392a6858c6aSchris $notes[] = sprintf($this->lang['note_group'], $conf['defaultgroup']); 3930440ff15Schris } 3940440ff15Schris 3950440ff15Schris ptln("<form action=\"".wl($ID)."\" method=\"post\">", $indent); 396634d7150SAndreas Gohr formSecurityToken(); 397c7b28ffdSAnika Henke ptln(" <div class=\"table\">", $indent); 3980440ff15Schris ptln(" <table class=\"inline\">", $indent); 3990440ff15Schris ptln(" <thead>", $indent); 4000440ff15Schris ptln(" <tr><th>".$this->lang["field"]."</th><th>".$this->lang["value"]."</th></tr>", $indent); 4010440ff15Schris ptln(" </thead>", $indent); 4020440ff15Schris ptln(" <tbody>", $indent); 40326fb387bSchris 4043a97d936SAndreas Gohr $this->htmlInputField( 40564159a61SAndreas Gohr $cmd . "_userid", 40664159a61SAndreas Gohr "userid", 40764159a61SAndreas Gohr $this->lang["user_id"], 40864159a61SAndreas Gohr $user, 4093a97d936SAndreas Gohr $this->auth->canDo("modLogin"), 41064159a61SAndreas Gohr true, 41164159a61SAndreas Gohr $indent + 6 41264159a61SAndreas Gohr ); 4133a97d936SAndreas Gohr $this->htmlInputField( 41464159a61SAndreas Gohr $cmd . "_userpass", 41564159a61SAndreas Gohr "userpass", 41664159a61SAndreas Gohr $this->lang["user_pass"], 41764159a61SAndreas Gohr "", 4183a97d936SAndreas Gohr $this->auth->canDo("modPass"), 41964159a61SAndreas Gohr false, 42064159a61SAndreas Gohr $indent + 6 42164159a61SAndreas Gohr ); 4223a97d936SAndreas Gohr $this->htmlInputField( 42364159a61SAndreas Gohr $cmd . "_userpass2", 42464159a61SAndreas Gohr "userpass2", 42564159a61SAndreas Gohr $lang["passchk"], 42664159a61SAndreas Gohr "", 4273a97d936SAndreas Gohr $this->auth->canDo("modPass"), 42864159a61SAndreas Gohr false, 42964159a61SAndreas Gohr $indent + 6 43064159a61SAndreas Gohr ); 4313a97d936SAndreas Gohr $this->htmlInputField( 43264159a61SAndreas Gohr $cmd . "_username", 43364159a61SAndreas Gohr "username", 43464159a61SAndreas Gohr $this->lang["user_name"], 43564159a61SAndreas Gohr $name, 4363a97d936SAndreas Gohr $this->auth->canDo("modName"), 43764159a61SAndreas Gohr true, 43864159a61SAndreas Gohr $indent + 6 43964159a61SAndreas Gohr ); 4403a97d936SAndreas Gohr $this->htmlInputField( 44164159a61SAndreas Gohr $cmd . "_usermail", 44264159a61SAndreas Gohr "usermail", 44364159a61SAndreas Gohr $this->lang["user_mail"], 44464159a61SAndreas Gohr $mail, 4453a97d936SAndreas Gohr $this->auth->canDo("modMail"), 44664159a61SAndreas Gohr true, 44764159a61SAndreas Gohr $indent + 6 44864159a61SAndreas Gohr ); 4493a97d936SAndreas Gohr $this->htmlInputField( 45064159a61SAndreas Gohr $cmd . "_usergroups", 45164159a61SAndreas Gohr "usergroups", 45264159a61SAndreas Gohr $this->lang["user_groups"], 45364159a61SAndreas Gohr $groups, 4543a97d936SAndreas Gohr $this->auth->canDo("modGroups"), 45564159a61SAndreas Gohr false, 45664159a61SAndreas Gohr $indent + 6 45764159a61SAndreas Gohr ); 45826fb387bSchris 4593a97d936SAndreas Gohr if ($this->auth->canDo("modPass")) { 460ee9498f5SChristopher Smith if ($cmd == 'add') { 461c3f4fb63SGina Haeussge $notes[] = $this->lang['note_pass']; 462ee9498f5SChristopher Smith } 463a6858c6aSchris if ($user) { 464a6858c6aSchris $notes[] = $this->lang['note_notify']; 465a6858c6aSchris } 466a6858c6aSchris 46764159a61SAndreas Gohr ptln("<tr><td><label for=\"".$cmd."_usernotify\" >". 46864159a61SAndreas Gohr $this->lang["user_notify"].": </label></td> 46964159a61SAndreas Gohr <td><input type=\"checkbox\" id=\"".$cmd."_usernotify\" name=\"usernotify\" value=\"1\" /> 47064159a61SAndreas Gohr </td></tr>", $indent); 471a6858c6aSchris } 472a6858c6aSchris 4730440ff15Schris ptln(" </tbody>", $indent); 4740440ff15Schris ptln(" <tbody>", $indent); 4750440ff15Schris ptln(" <tr>", $indent); 4760440ff15Schris ptln(" <td colspan=\"2\">", $indent); 4770440ff15Schris ptln(" <input type=\"hidden\" name=\"do\" value=\"admin\" />", $indent); 4780440ff15Schris ptln(" <input type=\"hidden\" name=\"page\" value=\"usermanager\" />", $indent); 4790440ff15Schris 4800440ff15Schris // save current $user, we need this to access details if the name is changed 4810440ff15Schris if ($user) 482f23f9594SAndreas Gohr ptln(" <input type=\"hidden\" name=\"userid_old\" value=\"".hsc($user)."\" />", $indent); 4830440ff15Schris 4843a97d936SAndreas Gohr $this->htmlFilterSettings($indent+10); 4850440ff15Schris 486ae614416SAnika Henke ptln(" <button type=\"submit\" name=\"fn[".$cmd."]\">".$this->lang[$cmd]."</button>", $indent); 4870440ff15Schris ptln(" </td>", $indent); 4880440ff15Schris ptln(" </tr>", $indent); 4890440ff15Schris ptln(" </tbody>", $indent); 4900440ff15Schris ptln(" </table>", $indent); 49145c19902SChristopher Smith 49245c19902SChristopher Smith if ($notes) { 49345c19902SChristopher Smith ptln(" <ul class=\"notes\">"); 49445c19902SChristopher Smith foreach ($notes as $note) { 495ae614416SAnika Henke ptln(" <li><span class=\"li\">".$note."</li>", $indent); 49645c19902SChristopher Smith } 49745c19902SChristopher Smith ptln(" </ul>"); 49845c19902SChristopher Smith } 499c7b28ffdSAnika Henke ptln(" </div>", $indent); 5000440ff15Schris ptln("</form>", $indent); 5010440ff15Schris } 5020440ff15Schris 503c5a7c0c6SGerrit Uitslag /** 504c5a7c0c6SGerrit Uitslag * Prints a inputfield 505c5a7c0c6SGerrit Uitslag * 506c5a7c0c6SGerrit Uitslag * @param string $id 507c5a7c0c6SGerrit Uitslag * @param string $name 508c5a7c0c6SGerrit Uitslag * @param string $label 509c5a7c0c6SGerrit Uitslag * @param string $value 510c5a7c0c6SGerrit Uitslag * @param bool $cando whether auth backend is capable to do this action 5119b82d43fSAndreas Gohr * @param bool $required is this field required? 512c5a7c0c6SGerrit Uitslag * @param int $indent 513c5a7c0c6SGerrit Uitslag */ 5143a97d936SAndreas Gohr protected function htmlInputField($id, $name, $label, $value, $cando, $required, $indent = 0) 5153a97d936SAndreas Gohr { 5167de12fceSAndreas Gohr $class = $cando ? '' : ' class="disabled"'; 5177de12fceSAndreas Gohr echo str_pad('', $indent); 5187de12fceSAndreas Gohr 519359e9417SChristopher Smith if ($name == 'userpass' || $name == 'userpass2') { 520d796a891SAndreas Gohr $fieldtype = 'password'; 521d796a891SAndreas Gohr $autocomp = 'autocomplete="off"'; 5227b3674bdSChristopher Smith } elseif ($name == 'usermail') { 5237b3674bdSChristopher Smith $fieldtype = 'email'; 5247b3674bdSChristopher Smith $autocomp = ''; 525d796a891SAndreas Gohr } else { 526d796a891SAndreas Gohr $fieldtype = 'text'; 527d796a891SAndreas Gohr $autocomp = ''; 528d796a891SAndreas Gohr } 529f23f9594SAndreas Gohr $value = hsc($value); 530d796a891SAndreas Gohr 5317de12fceSAndreas Gohr echo "<tr $class>"; 5327de12fceSAndreas Gohr echo "<td><label for=\"$id\" >$label: </label></td>"; 5337de12fceSAndreas Gohr echo "<td>"; 5347de12fceSAndreas Gohr if ($cando) { 5359b82d43fSAndreas Gohr $req = ''; 5369b82d43fSAndreas Gohr if ($required) $req = 'required="required"'; 53764159a61SAndreas Gohr echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\" 53864159a61SAndreas Gohr value=\"$value\" class=\"edit\" $autocomp $req />"; 5397de12fceSAndreas Gohr } else { 5407de12fceSAndreas Gohr echo "<input type=\"hidden\" name=\"$name\" value=\"$value\" />"; 54164159a61SAndreas Gohr echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\" 54264159a61SAndreas Gohr value=\"$value\" class=\"edit disabled\" disabled=\"disabled\" />"; 5437de12fceSAndreas Gohr } 5447de12fceSAndreas Gohr echo "</td>"; 5457de12fceSAndreas Gohr echo "</tr>"; 54626fb387bSchris } 54726fb387bSchris 548c5a7c0c6SGerrit Uitslag /** 549c5a7c0c6SGerrit Uitslag * Returns htmlescaped filter value 550c5a7c0c6SGerrit Uitslag * 551c5a7c0c6SGerrit Uitslag * @param string $key name of search field 552c5a7c0c6SGerrit Uitslag * @return string html escaped value 553c5a7c0c6SGerrit Uitslag */ 5543a97d936SAndreas Gohr protected function htmlFilter($key) 5553a97d936SAndreas Gohr { 5563a97d936SAndreas Gohr if (empty($this->filter)) return ''; 5573a97d936SAndreas Gohr return (isset($this->filter[$key]) ? hsc($this->filter[$key]) : ''); 5580440ff15Schris } 5590440ff15Schris 560c5a7c0c6SGerrit Uitslag /** 561c5a7c0c6SGerrit Uitslag * Print hidden inputs with the current filter values 562c5a7c0c6SGerrit Uitslag * 563c5a7c0c6SGerrit Uitslag * @param int $indent 564c5a7c0c6SGerrit Uitslag */ 5653a97d936SAndreas Gohr protected function htmlFilterSettings($indent = 0) 5663a97d936SAndreas Gohr { 5670440ff15Schris 5683a97d936SAndreas Gohr ptln("<input type=\"hidden\" name=\"start\" value=\"".$this->start."\" />", $indent); 5690440ff15Schris 5703a97d936SAndreas Gohr foreach ($this->filter as $key => $filter) { 5710440ff15Schris ptln("<input type=\"hidden\" name=\"filter[".$key."]\" value=\"".hsc($filter)."\" />", $indent); 5720440ff15Schris } 5730440ff15Schris } 5740440ff15Schris 575c5a7c0c6SGerrit Uitslag /** 576c5a7c0c6SGerrit Uitslag * Print import form and summary of previous import 577c5a7c0c6SGerrit Uitslag * 578c5a7c0c6SGerrit Uitslag * @param int $indent 579c5a7c0c6SGerrit Uitslag */ 5803a97d936SAndreas Gohr protected function htmlImportForm($indent = 0) 5813a97d936SAndreas Gohr { 582ae1afd2fSChristopher Smith global $ID; 583ae1afd2fSChristopher Smith 584*54cc7aa4SAndreas Gohr $failure_download_link = wl($ID, ['do'=>'admin', 'page'=>'usermanager', 'fn[importfails]'=>1]); 585ae1afd2fSChristopher Smith 586ae1afd2fSChristopher Smith ptln('<div class="level2 import_users">', $indent); 587ae1afd2fSChristopher Smith print $this->locale_xhtml('import'); 588ae1afd2fSChristopher Smith ptln(' <form action="'.wl($ID).'" method="post" enctype="multipart/form-data">', $indent); 589ae1afd2fSChristopher Smith formSecurityToken(); 590b59cff8bSGerrit Uitslag ptln(' <label>'.$this->lang['import_userlistcsv'].'<input type="file" name="import" /></label>', $indent); 591ae614416SAnika Henke ptln(' <button type="submit" name="fn[import]">'.$this->lang['import'].'</button>', $indent); 592ae1afd2fSChristopher Smith ptln(' <input type="hidden" name="do" value="admin" />', $indent); 593ae1afd2fSChristopher Smith ptln(' <input type="hidden" name="page" value="usermanager" />', $indent); 594ae1afd2fSChristopher Smith 5953a97d936SAndreas Gohr $this->htmlFilterSettings($indent+4); 596ae1afd2fSChristopher Smith ptln(' </form>', $indent); 597ae1afd2fSChristopher Smith ptln('</div>'); 598ae1afd2fSChristopher Smith 599ae1afd2fSChristopher Smith // list failures from the previous import 6003a97d936SAndreas Gohr if ($this->import_failures) { 6013a97d936SAndreas Gohr $digits = strlen(count($this->import_failures)); 602ae1afd2fSChristopher Smith ptln('<div class="level3 import_failures">', $indent); 603b59cff8bSGerrit Uitslag ptln(' <h3>'.$this->lang['import_header'].'</h3>'); 604ae1afd2fSChristopher Smith ptln(' <table class="import_failures">', $indent); 605ae1afd2fSChristopher Smith ptln(' <thead>', $indent); 606ae1afd2fSChristopher Smith ptln(' <tr>', $indent); 607ae1afd2fSChristopher Smith ptln(' <th class="line">'.$this->lang['line'].'</th>', $indent); 608ae1afd2fSChristopher Smith ptln(' <th class="error">'.$this->lang['error'].'</th>', $indent); 609ae1afd2fSChristopher Smith ptln(' <th class="userid">'.$this->lang['user_id'].'</th>', $indent); 610ae1afd2fSChristopher Smith ptln(' <th class="username">'.$this->lang['user_name'].'</th>', $indent); 611ae1afd2fSChristopher Smith ptln(' <th class="usermail">'.$this->lang['user_mail'].'</th>', $indent); 612ae1afd2fSChristopher Smith ptln(' <th class="usergroups">'.$this->lang['user_groups'].'</th>', $indent); 613ae1afd2fSChristopher Smith ptln(' </tr>', $indent); 614ae1afd2fSChristopher Smith ptln(' </thead>', $indent); 615ae1afd2fSChristopher Smith ptln(' <tbody>', $indent); 6163a97d936SAndreas Gohr foreach ($this->import_failures as $line => $failure) { 617ae1afd2fSChristopher Smith ptln(' <tr>', $indent); 618ae1afd2fSChristopher Smith ptln(' <td class="lineno"> '.sprintf('%0'.$digits.'d', $line).' </td>', $indent); 619ae1afd2fSChristopher Smith ptln(' <td class="error">' .$failure['error'].' </td>', $indent); 620ae1afd2fSChristopher Smith ptln(' <td class="field userid"> '.hsc($failure['user'][0]).' </td>', $indent); 621ae1afd2fSChristopher Smith ptln(' <td class="field username"> '.hsc($failure['user'][2]).' </td>', $indent); 622ae1afd2fSChristopher Smith ptln(' <td class="field usermail"> '.hsc($failure['user'][3]).' </td>', $indent); 623ae1afd2fSChristopher Smith ptln(' <td class="field usergroups"> '.hsc($failure['user'][4]).' </td>', $indent); 624ae1afd2fSChristopher Smith ptln(' </tr>', $indent); 625ae1afd2fSChristopher Smith } 626ae1afd2fSChristopher Smith ptln(' </tbody>', $indent); 627ae1afd2fSChristopher Smith ptln(' </table>', $indent); 628b59cff8bSGerrit Uitslag ptln(' <p><a href="'.$failure_download_link.'">'.$this->lang['import_downloadfailures'].'</a></p>'); 629ae1afd2fSChristopher Smith ptln('</div>'); 630ae1afd2fSChristopher Smith } 631ae1afd2fSChristopher Smith } 632ae1afd2fSChristopher Smith 633c5a7c0c6SGerrit Uitslag /** 634c5a7c0c6SGerrit Uitslag * Add an user to auth backend 635c5a7c0c6SGerrit Uitslag * 636c5a7c0c6SGerrit Uitslag * @return bool whether succesful 637c5a7c0c6SGerrit Uitslag */ 6383a97d936SAndreas Gohr protected function addUser() 6393a97d936SAndreas Gohr { 64000d58927SMichael Hamann global $INPUT; 641634d7150SAndreas Gohr if (!checkSecurityToken()) return false; 6423a97d936SAndreas Gohr if (!$this->auth->canDo('addUser')) return false; 6430440ff15Schris 644*54cc7aa4SAndreas Gohr [$user, $pass, $name, $mail, $grps, $passconfirm] = $this->retrieveUser(); 6450440ff15Schris if (empty($user)) return false; 6466733c4d7SChris Smith 6473a97d936SAndreas Gohr if ($this->auth->canDo('modPass')) { 648c3f4fb63SGina Haeussge if (empty($pass)) { 64900d58927SMichael Hamann if ($INPUT->has('usernotify')) { 6508a285f7fSAndreas Gohr $pass = auth_pwgen($user); 651c3f4fb63SGina Haeussge } else { 65260b9901bSAndreas Gohr msg($this->lang['add_fail'], -1); 65309a5dcd6SMichael Große msg($this->lang['addUser_error_missing_pass'], -1); 65460b9901bSAndreas Gohr return false; 65560b9901bSAndreas Gohr } 656*54cc7aa4SAndreas Gohr } elseif (!$this->verifyPassword($pass, $passconfirm)) { 65709a5dcd6SMichael Große msg($this->lang['add_fail'], -1); 65809a5dcd6SMichael Große msg($this->lang['addUser_error_pass_not_identical'], -1); 659359e9417SChristopher Smith return false; 660359e9417SChristopher Smith } 661*54cc7aa4SAndreas Gohr } elseif (!empty($pass)) { 6626733c4d7SChris Smith msg($this->lang['add_fail'], -1); 66309a5dcd6SMichael Große msg($this->lang['addUser_error_modPass_disabled'], -1); 6646733c4d7SChris Smith return false; 6656733c4d7SChris Smith } 6666733c4d7SChris Smith 6673a97d936SAndreas Gohr if ($this->auth->canDo('modName')) { 6686733c4d7SChris Smith if (empty($name)) { 6696733c4d7SChris Smith msg($this->lang['add_fail'], -1); 67009a5dcd6SMichael Große msg($this->lang['addUser_error_name_missing'], -1); 6716733c4d7SChris Smith return false; 6726733c4d7SChris Smith } 673*54cc7aa4SAndreas Gohr } elseif (!empty($name)) { 67409a5dcd6SMichael Große msg($this->lang['add_fail'], -1); 67509a5dcd6SMichael Große msg($this->lang['addUser_error_modName_disabled'], -1); 6766733c4d7SChris Smith return false; 6776733c4d7SChris Smith } 6786733c4d7SChris Smith 6793a97d936SAndreas Gohr if ($this->auth->canDo('modMail')) { 6806733c4d7SChris Smith if (empty($mail)) { 6816733c4d7SChris Smith msg($this->lang['add_fail'], -1); 68209a5dcd6SMichael Große msg($this->lang['addUser_error_mail_missing'], -1); 6836733c4d7SChris Smith return false; 6846733c4d7SChris Smith } 685*54cc7aa4SAndreas Gohr } elseif (!empty($mail)) { 68609a5dcd6SMichael Große msg($this->lang['add_fail'], -1); 68709a5dcd6SMichael Große msg($this->lang['addUser_error_modMail_disabled'], -1); 6886733c4d7SChris Smith return false; 6896733c4d7SChris Smith } 6900440ff15Schris 691*54cc7aa4SAndreas Gohr if ($ok = $this->auth->triggerUserMod('create', [$user, $pass, $name, $mail, $grps])) { 692a6858c6aSchris msg($this->lang['add_ok'], 1); 693a6858c6aSchris 69400d58927SMichael Hamann if ($INPUT->has('usernotify') && $pass) { 6953a97d936SAndreas Gohr $this->notifyUser($user, $pass); 696a6858c6aSchris } 697a6858c6aSchris } else { 69860b9901bSAndreas Gohr msg($this->lang['add_fail'], -1); 69909a5dcd6SMichael Große msg($this->lang['addUser_error_create_event_failed'], -1); 700a6858c6aSchris } 701a6858c6aSchris 702a6858c6aSchris return $ok; 7030440ff15Schris } 7040440ff15Schris 7050440ff15Schris /** 706c5a7c0c6SGerrit Uitslag * Delete user from auth backend 707c5a7c0c6SGerrit Uitslag * 708c5a7c0c6SGerrit Uitslag * @return bool whether succesful 7090440ff15Schris */ 7103a97d936SAndreas Gohr protected function deleteUser() 7113a97d936SAndreas Gohr { 71200d58927SMichael Hamann global $conf, $INPUT; 7139ec82636SAndreas Gohr 714634d7150SAndreas Gohr if (!checkSecurityToken()) return false; 7153a97d936SAndreas Gohr if (!$this->auth->canDo('delUser')) return false; 7160440ff15Schris 71700d58927SMichael Hamann $selected = $INPUT->arr('delete'); 71800d58927SMichael Hamann if (empty($selected)) return false; 7190440ff15Schris $selected = array_keys($selected); 7200440ff15Schris 721c9a8f912SMichael Klier if (in_array($_SERVER['REMOTE_USER'], $selected)) { 722c9a8f912SMichael Klier msg("You can't delete yourself!", -1); 723c9a8f912SMichael Klier return false; 724c9a8f912SMichael Klier } 725c9a8f912SMichael Klier 726*54cc7aa4SAndreas Gohr $count = $this->auth->triggerUserMod('delete', [$selected]); 7270440ff15Schris if ($count == count($selected)) { 7280440ff15Schris $text = str_replace('%d', $count, $this->lang['delete_ok']); 7290440ff15Schris msg("$text.", 1); 7300440ff15Schris } else { 7310440ff15Schris $part1 = str_replace('%d', $count, $this->lang['delete_ok']); 7320440ff15Schris $part2 = str_replace('%d', (count($selected)-$count), $this->lang['delete_fail']); 7330440ff15Schris msg("$part1, $part2", -1); 7340440ff15Schris } 73578c7c8c9Schris 7369ec82636SAndreas Gohr // invalidate all sessions 7379ec82636SAndreas Gohr io_saveFile($conf['cachedir'].'/sessionpurge', time()); 7389ec82636SAndreas Gohr 73978c7c8c9Schris return true; 74078c7c8c9Schris } 74178c7c8c9Schris 74278c7c8c9Schris /** 74378c7c8c9Schris * Edit user (a user has been selected for editing) 744c5a7c0c6SGerrit Uitslag * 745c5a7c0c6SGerrit Uitslag * @param string $param id of the user 746c5a7c0c6SGerrit Uitslag * @return bool whether succesful 74778c7c8c9Schris */ 7483a97d936SAndreas Gohr protected function editUser($param) 7493a97d936SAndreas Gohr { 750634d7150SAndreas Gohr if (!checkSecurityToken()) return false; 7513a97d936SAndreas Gohr if (!$this->auth->canDo('UserMod')) return false; 7523a97d936SAndreas Gohr $user = $this->auth->cleanUser(preg_replace('/.*[:\/]/', '', $param)); 7533a97d936SAndreas Gohr $userdata = $this->auth->getUserData($user); 75478c7c8c9Schris 75578c7c8c9Schris // no user found? 75678c7c8c9Schris if (!$userdata) { 75778c7c8c9Schris msg($this->lang['edit_usermissing'], -1); 75878c7c8c9Schris return false; 75978c7c8c9Schris } 76078c7c8c9Schris 7613a97d936SAndreas Gohr $this->edit_user = $user; 7623a97d936SAndreas Gohr $this->edit_userdata = $userdata; 76378c7c8c9Schris 76478c7c8c9Schris return true; 7650440ff15Schris } 7660440ff15Schris 7670440ff15Schris /** 768c5a7c0c6SGerrit Uitslag * Modify user in the auth backend (modified user data has been recieved) 769c5a7c0c6SGerrit Uitslag * 770c5a7c0c6SGerrit Uitslag * @return bool whether succesful 7710440ff15Schris */ 7723a97d936SAndreas Gohr protected function modifyUser() 7733a97d936SAndreas Gohr { 77400d58927SMichael Hamann global $conf, $INPUT; 7759ec82636SAndreas Gohr 776634d7150SAndreas Gohr if (!checkSecurityToken()) return false; 7773a97d936SAndreas Gohr if (!$this->auth->canDo('UserMod')) return false; 7780440ff15Schris 77926fb387bSchris // get currently valid user data 7803a97d936SAndreas Gohr $olduser = $this->auth->cleanUser(preg_replace('/.*[:\/]/', '', $INPUT->str('userid_old'))); 7813a97d936SAndreas Gohr $oldinfo = $this->auth->getUserData($olduser); 782073766c6Smatthiasgrimm 78326fb387bSchris // get new user data subject to change 784*54cc7aa4SAndreas Gohr [$newuser, $newpass, $newname, $newmail, $newgrps, $passconfirm] = $this->retrieveUser(); 785073766c6Smatthiasgrimm if (empty($newuser)) return false; 7860440ff15Schris 787*54cc7aa4SAndreas Gohr $changes = []; 788073766c6Smatthiasgrimm if ($newuser != $olduser) { 7893a97d936SAndreas Gohr if (!$this->auth->canDo('modLogin')) { // sanity check, shouldn't be possible 79026fb387bSchris msg($this->lang['update_fail'], -1); 79126fb387bSchris return false; 79226fb387bSchris } 79326fb387bSchris 79426fb387bSchris // check if $newuser already exists 7953a97d936SAndreas Gohr if ($this->auth->getUserData($newuser)) { 796073766c6Smatthiasgrimm msg(sprintf($this->lang['update_exists'], $newuser), -1); 797a6858c6aSchris $re_edit = true; 7980440ff15Schris } else { 799073766c6Smatthiasgrimm $changes['user'] = $newuser; 8000440ff15Schris } 80193eefc2fSAndreas Gohr } 8023a97d936SAndreas Gohr if ($this->auth->canDo('modPass')) { 8032400ddcbSChristopher Smith if ($newpass || $passconfirm) { 8043a97d936SAndreas Gohr if ($this->verifyPassword($newpass, $passconfirm)) { 805359e9417SChristopher Smith $changes['pass'] = $newpass; 806359e9417SChristopher Smith } else { 807359e9417SChristopher Smith return false; 808359e9417SChristopher Smith } 809*54cc7aa4SAndreas Gohr } elseif ($INPUT->has('usernotify')) { 810359e9417SChristopher Smith // no new password supplied, check if we need to generate one (or it stays unchanged) 811359e9417SChristopher Smith $changes['pass'] = auth_pwgen($olduser); 812359e9417SChristopher Smith } 813359e9417SChristopher Smith } 8140440ff15Schris 8153a97d936SAndreas Gohr if (!empty($newname) && $this->auth->canDo('modName') && $newname != $oldinfo['name']) { 816073766c6Smatthiasgrimm $changes['name'] = $newname; 81740d72af6SChristopher Smith } 8183a97d936SAndreas Gohr if (!empty($newmail) && $this->auth->canDo('modMail') && $newmail != $oldinfo['mail']) { 819073766c6Smatthiasgrimm $changes['mail'] = $newmail; 82040d72af6SChristopher Smith } 8213a97d936SAndreas Gohr if (!empty($newgrps) && $this->auth->canDo('modGroups') && $newgrps != $oldinfo['grps']) { 822073766c6Smatthiasgrimm $changes['grps'] = $newgrps; 82340d72af6SChristopher Smith } 8240440ff15Schris 825*54cc7aa4SAndreas Gohr if ($ok = $this->auth->triggerUserMod('modify', [$olduser, $changes])) { 8260440ff15Schris msg($this->lang['update_ok'], 1); 827a6858c6aSchris 8286ed3476bSChristopher Smith if ($INPUT->has('usernotify') && !empty($changes['pass'])) { 829a6858c6aSchris $notify = empty($changes['user']) ? $olduser : $newuser; 8303a97d936SAndreas Gohr $this->notifyUser($notify, $changes['pass']); 831a6858c6aSchris } 832a6858c6aSchris 8339ec82636SAndreas Gohr // invalidate all sessions 8349ec82636SAndreas Gohr io_saveFile($conf['cachedir'].'/sessionpurge', time()); 8350440ff15Schris } else { 8360440ff15Schris msg($this->lang['update_fail'], -1); 8370440ff15Schris } 83878c7c8c9Schris 839a6858c6aSchris if (!empty($re_edit)) { 8403a97d936SAndreas Gohr $this->editUser($olduser); 8410440ff15Schris } 8420440ff15Schris 843a6858c6aSchris return $ok; 844a6858c6aSchris } 845a6858c6aSchris 846a6858c6aSchris /** 847c5a7c0c6SGerrit Uitslag * Send password change notification email 848c5a7c0c6SGerrit Uitslag * 849c5a7c0c6SGerrit Uitslag * @param string $user id of user 850c5a7c0c6SGerrit Uitslag * @param string $password plain text 851c5a7c0c6SGerrit Uitslag * @param bool $status_alert whether status alert should be shown 852c5a7c0c6SGerrit Uitslag * @return bool whether succesful 853a6858c6aSchris */ 8543a97d936SAndreas Gohr protected function notifyUser($user, $password, $status_alert = true) 8553a97d936SAndreas Gohr { 856a6858c6aSchris 857a6858c6aSchris if ($sent = auth_sendPassword($user, $password)) { 858328143f8SChristopher Smith if ($status_alert) { 859a6858c6aSchris msg($this->lang['notify_ok'], 1); 860328143f8SChristopher Smith } 861*54cc7aa4SAndreas Gohr } elseif ($status_alert) { 862a6858c6aSchris msg($this->lang['notify_fail'], -1); 863a6858c6aSchris } 864a6858c6aSchris 865a6858c6aSchris return $sent; 866a6858c6aSchris } 867a6858c6aSchris 868a6858c6aSchris /** 869359e9417SChristopher Smith * Verify password meets minimum requirements 870359e9417SChristopher Smith * :TODO: extend to support password strength 871359e9417SChristopher Smith * 872359e9417SChristopher Smith * @param string $password candidate string for new password 873359e9417SChristopher Smith * @param string $confirm repeated password for confirmation 874359e9417SChristopher Smith * @return bool true if meets requirements, false otherwise 875359e9417SChristopher Smith */ 8763a97d936SAndreas Gohr protected function verifyPassword($password, $confirm) 8773a97d936SAndreas Gohr { 878be9008d3SChristopher Smith global $lang; 879359e9417SChristopher Smith 8802400ddcbSChristopher Smith if (empty($password) && empty($confirm)) { 881359e9417SChristopher Smith return false; 882359e9417SChristopher Smith } 883359e9417SChristopher Smith 884359e9417SChristopher Smith if ($password !== $confirm) { 885be9008d3SChristopher Smith msg($lang['regbadpass'], -1); 886359e9417SChristopher Smith return false; 887359e9417SChristopher Smith } 888359e9417SChristopher Smith 889359e9417SChristopher Smith // :TODO: test password for required strength 890359e9417SChristopher Smith 891359e9417SChristopher Smith // if we make it this far the password is good 892359e9417SChristopher Smith return true; 893359e9417SChristopher Smith } 894359e9417SChristopher Smith 895359e9417SChristopher Smith /** 896c5a7c0c6SGerrit Uitslag * Retrieve & clean user data from the form 897a6858c6aSchris * 898c5a7c0c6SGerrit Uitslag * @param bool $clean whether the cleanUser method of the authentication backend is applied 899a6858c6aSchris * @return array (user, password, full name, email, array(groups)) 9000440ff15Schris */ 9013a97d936SAndreas Gohr protected function retrieveUser($clean = true) 9023a97d936SAndreas Gohr { 903c5a7c0c6SGerrit Uitslag /** @var DokuWiki_Auth_Plugin $auth */ 9047441e340SAndreas Gohr global $auth; 905fbfbbe8aSHakan Sandell global $INPUT; 9060440ff15Schris 907*54cc7aa4SAndreas Gohr $user = []; 908fbfbbe8aSHakan Sandell $user[0] = ($clean) ? $auth->cleanUser($INPUT->str('userid')) : $INPUT->str('userid'); 909fbfbbe8aSHakan Sandell $user[1] = $INPUT->str('userpass'); 910fbfbbe8aSHakan Sandell $user[2] = $INPUT->str('username'); 911fbfbbe8aSHakan Sandell $user[3] = $INPUT->str('usermail'); 912fbfbbe8aSHakan Sandell $user[4] = explode(',', $INPUT->str('usergroups')); 913359e9417SChristopher Smith $user[5] = $INPUT->str('userpass2'); // repeated password for confirmation 9140440ff15Schris 9157441e340SAndreas Gohr $user[4] = array_map('trim', $user[4]); 916*54cc7aa4SAndreas Gohr if ($clean) $user[4] = array_map([$auth, 'cleanGroup'], $user[4]); 9177441e340SAndreas Gohr $user[4] = array_filter($user[4]); 9187441e340SAndreas Gohr $user[4] = array_unique($user[4]); 919*54cc7aa4SAndreas Gohr if ($user[4] === []) $user[4] = null; 9200440ff15Schris 9210440ff15Schris return $user; 9220440ff15Schris } 9230440ff15Schris 924c5a7c0c6SGerrit Uitslag /** 925c5a7c0c6SGerrit Uitslag * Set the filter with the current search terms or clear the filter 926c5a7c0c6SGerrit Uitslag * 927c5a7c0c6SGerrit Uitslag * @param string $op 'new' or 'clear' 928c5a7c0c6SGerrit Uitslag */ 9293a97d936SAndreas Gohr protected function setFilter($op) 9303a97d936SAndreas Gohr { 9310440ff15Schris 932*54cc7aa4SAndreas Gohr $this->filter = []; 9330440ff15Schris 9340440ff15Schris if ($op == 'new') { 935*54cc7aa4SAndreas Gohr [$user, , $name, $mail, $grps] = $this->retrieveUser(false); 9360440ff15Schris 9373a97d936SAndreas Gohr if (!empty($user)) $this->filter['user'] = $user; 9383a97d936SAndreas Gohr if (!empty($name)) $this->filter['name'] = $name; 9393a97d936SAndreas Gohr if (!empty($mail)) $this->filter['mail'] = $mail; 940*54cc7aa4SAndreas Gohr if (!empty($grps)) $this->filter['grps'] = implode('|', $grps); 9410440ff15Schris } 9420440ff15Schris } 9430440ff15Schris 944c5a7c0c6SGerrit Uitslag /** 945c5a7c0c6SGerrit Uitslag * Get the current search terms 946c5a7c0c6SGerrit Uitslag * 947c5a7c0c6SGerrit Uitslag * @return array 948c5a7c0c6SGerrit Uitslag */ 9493a97d936SAndreas Gohr protected function retrieveFilter() 9503a97d936SAndreas Gohr { 951fbfbbe8aSHakan Sandell global $INPUT; 9520440ff15Schris 953fbfbbe8aSHakan Sandell $t_filter = $INPUT->arr('filter'); 9540440ff15Schris 9550440ff15Schris // messy, but this way we ensure we aren't getting any additional crap from malicious users 956*54cc7aa4SAndreas Gohr $filter = []; 9570440ff15Schris 9580440ff15Schris if (isset($t_filter['user'])) $filter['user'] = $t_filter['user']; 9590440ff15Schris if (isset($t_filter['name'])) $filter['name'] = $t_filter['name']; 9600440ff15Schris if (isset($t_filter['mail'])) $filter['mail'] = $t_filter['mail']; 9610440ff15Schris if (isset($t_filter['grps'])) $filter['grps'] = $t_filter['grps']; 9620440ff15Schris 9630440ff15Schris return $filter; 9640440ff15Schris } 9650440ff15Schris 966c5a7c0c6SGerrit Uitslag /** 967c5a7c0c6SGerrit Uitslag * Validate and improve the pagination values 968c5a7c0c6SGerrit Uitslag */ 9693a97d936SAndreas Gohr protected function validatePagination() 9703a97d936SAndreas Gohr { 9710440ff15Schris 9723a97d936SAndreas Gohr if ($this->start >= $this->users_total) { 9733a97d936SAndreas Gohr $this->start = $this->users_total - $this->pagesize; 9740440ff15Schris } 9753a97d936SAndreas Gohr if ($this->start < 0) $this->start = 0; 9760440ff15Schris 9773a97d936SAndreas Gohr $this->last = min($this->users_total, $this->start + $this->pagesize); 9780440ff15Schris } 9790440ff15Schris 980c5a7c0c6SGerrit Uitslag /** 981c5a7c0c6SGerrit Uitslag * Return an array of strings to enable/disable pagination buttons 982c5a7c0c6SGerrit Uitslag * 983c5a7c0c6SGerrit Uitslag * @return array with enable/disable attributes 9840440ff15Schris */ 9853a97d936SAndreas Gohr protected function pagination() 9863a97d936SAndreas Gohr { 9870440ff15Schris 98851d94d49Schris $disabled = 'disabled="disabled"'; 98951d94d49Schris 990*54cc7aa4SAndreas Gohr $buttons = []; 9913a97d936SAndreas Gohr $buttons['start'] = $buttons['prev'] = ($this->start == 0) ? $disabled : ''; 99251d94d49Schris 9933a97d936SAndreas Gohr if ($this->users_total == -1) { 99451d94d49Schris $buttons['last'] = $disabled; 99551d94d49Schris $buttons['next'] = ''; 99651d94d49Schris } else { 99764159a61SAndreas Gohr $buttons['last'] = $buttons['next'] = 9983a97d936SAndreas Gohr (($this->start + $this->pagesize) >= $this->users_total) ? $disabled : ''; 99951d94d49Schris } 10000440ff15Schris 10013a97d936SAndreas Gohr if ($this->lastdisabled) { 1002462e9e37SMichael Große $buttons['last'] = $disabled; 1003462e9e37SMichael Große } 1004462e9e37SMichael Große 10050440ff15Schris return $buttons; 10060440ff15Schris } 10075c967d3dSChristopher Smith 1008c5a7c0c6SGerrit Uitslag /** 1009c5a7c0c6SGerrit Uitslag * Export a list of users in csv format using the current filter criteria 10105c967d3dSChristopher Smith */ 10113a97d936SAndreas Gohr protected function exportCSV() 10123a97d936SAndreas Gohr { 10135c967d3dSChristopher Smith // list of users for export - based on current filter criteria 10143a97d936SAndreas Gohr $user_list = $this->auth->retrieveUsers(0, 0, $this->filter); 1015*54cc7aa4SAndreas Gohr $column_headings = [ 10165c967d3dSChristopher Smith $this->lang["user_id"], 10175c967d3dSChristopher Smith $this->lang["user_name"], 10185c967d3dSChristopher Smith $this->lang["user_mail"], 10195c967d3dSChristopher Smith $this->lang["user_groups"] 1020*54cc7aa4SAndreas Gohr ]; 10215c967d3dSChristopher Smith 10225c967d3dSChristopher Smith // ============================================================================================== 10235c967d3dSChristopher Smith // GENERATE OUTPUT 10245c967d3dSChristopher Smith // normal headers for downloading... 10255c967d3dSChristopher Smith header('Content-type: text/csv;charset=utf-8'); 10265c967d3dSChristopher Smith header('Content-Disposition: attachment; filename="wikiusers.csv"'); 10275c967d3dSChristopher Smith# // for debugging assistance, send as text plain to the browser 10285c967d3dSChristopher Smith# header('Content-type: text/plain;charset=utf-8'); 10295c967d3dSChristopher Smith 10305c967d3dSChristopher Smith // output the csv 10315c967d3dSChristopher Smith $fd = fopen('php://output', 'w'); 10325c967d3dSChristopher Smith fputcsv($fd, $column_headings); 10335c967d3dSChristopher Smith foreach ($user_list as $user => $info) { 1034*54cc7aa4SAndreas Gohr $line = [$user, $info['name'], $info['mail'], implode(',', $info['grps'])]; 10355c967d3dSChristopher Smith fputcsv($fd, $line); 10365c967d3dSChristopher Smith } 10375c967d3dSChristopher Smith fclose($fd); 10383a97d936SAndreas Gohr if (defined('DOKU_UNITTEST')) { 10393a97d936SAndreas Gohr return; 10403a97d936SAndreas Gohr } 1041b2c01466SChristopher Smith 10425c967d3dSChristopher Smith die; 10435c967d3dSChristopher Smith } 1044ae1afd2fSChristopher Smith 1045c5a7c0c6SGerrit Uitslag /** 1046c5a7c0c6SGerrit Uitslag * Import a file of users in csv format 1047ae1afd2fSChristopher Smith * 1048ae1afd2fSChristopher Smith * csv file should have 4 columns, user_id, full name, email, groups (comma separated) 1049c5a7c0c6SGerrit Uitslag * 10505ba64050SChristopher Smith * @return bool whether successful 1051ae1afd2fSChristopher Smith */ 10523a97d936SAndreas Gohr protected function importCSV() 10533a97d936SAndreas Gohr { 1054ae1afd2fSChristopher Smith // check we are allowed to add users 1055ae1afd2fSChristopher Smith if (!checkSecurityToken()) return false; 10563a97d936SAndreas Gohr if (!$this->auth->canDo('addUser')) return false; 1057ae1afd2fSChristopher Smith 1058ae1afd2fSChristopher Smith // check file uploaded ok. 10593a97d936SAndreas Gohr if (empty($_FILES['import']['size']) || 10603a97d936SAndreas Gohr !empty($_FILES['import']['error']) && $this->isUploadedFile($_FILES['import']['tmp_name']) 106164159a61SAndreas Gohr ) { 1062ae1afd2fSChristopher Smith msg($this->lang['import_error_upload'], -1); 1063ae1afd2fSChristopher Smith return false; 1064ae1afd2fSChristopher Smith } 1065ae1afd2fSChristopher Smith // retrieve users from the file 1066*54cc7aa4SAndreas Gohr $this->import_failures = []; 1067ae1afd2fSChristopher Smith $import_success_count = 0; 1068ae1afd2fSChristopher Smith $import_fail_count = 0; 1069ae1afd2fSChristopher Smith $line = 0; 1070ae1afd2fSChristopher Smith $fd = fopen($_FILES['import']['tmp_name'], 'r'); 1071ae1afd2fSChristopher Smith if ($fd) { 1072ae1afd2fSChristopher Smith while ($csv = fgets($fd)) { 1073*54cc7aa4SAndreas Gohr if (!Clean::isUtf8($csv)) { 1074efcec72bSChristopher Smith $csv = utf8_encode($csv); 1075efcec72bSChristopher Smith } 1076d0c0a5c4SAnika Henke $raw = str_getcsv($csv); 1077ae1afd2fSChristopher Smith $error = ''; // clean out any errors from the previous line 1078ae1afd2fSChristopher Smith // data checks... 1079ae1afd2fSChristopher Smith if (1 == ++$line) { 1080ae1afd2fSChristopher Smith if ($raw[0] == 'user_id' || $raw[0] == $this->lang['user_id']) continue; // skip headers 1081ae1afd2fSChristopher Smith } 1082ae1afd2fSChristopher Smith if (count($raw) < 4) { // need at least four fields 1083ae1afd2fSChristopher Smith $import_fail_count++; 1084ae1afd2fSChristopher Smith $error = sprintf($this->lang['import_error_fields'], count($raw)); 1085*54cc7aa4SAndreas Gohr $this->import_failures[$line] = ['error' => $error, 'user' => $raw, 'orig' => $csv]; 1086ae1afd2fSChristopher Smith continue; 1087ae1afd2fSChristopher Smith } 1088ae1afd2fSChristopher Smith array_splice($raw, 1, 0, auth_pwgen()); // splice in a generated password 10893a97d936SAndreas Gohr $clean = $this->cleanImportUser($raw, $error); 10903a97d936SAndreas Gohr if ($clean && $this->importUser($clean, $error)) { 10913a97d936SAndreas Gohr $sent = $this->notifyUser($clean[0], $clean[1], false); 1092328143f8SChristopher Smith if (!$sent) { 1093328143f8SChristopher Smith msg(sprintf($this->lang['import_notify_fail'], $clean[0], $clean[3]), -1); 1094328143f8SChristopher Smith } 1095ae1afd2fSChristopher Smith $import_success_count++; 1096ae1afd2fSChristopher Smith } else { 1097ae1afd2fSChristopher Smith $import_fail_count++; 1098e73725baSChristopher Smith array_splice($raw, 1, 1); // remove the spliced in password 1099*54cc7aa4SAndreas Gohr $this->import_failures[$line] = ['error' => $error, 'user' => $raw, 'orig' => $csv]; 1100ae1afd2fSChristopher Smith } 1101ae1afd2fSChristopher Smith } 110264159a61SAndreas Gohr msg( 110364159a61SAndreas Gohr sprintf( 110464159a61SAndreas Gohr $this->lang['import_success_count'], 110564159a61SAndreas Gohr ($import_success_count + $import_fail_count), 110664159a61SAndreas Gohr $import_success_count 110764159a61SAndreas Gohr ), 110864159a61SAndreas Gohr ($import_success_count ? 1 : -1) 110964159a61SAndreas Gohr ); 1110ae1afd2fSChristopher Smith if ($import_fail_count) { 1111ae1afd2fSChristopher Smith msg(sprintf($this->lang['import_failure_count'], $import_fail_count), -1); 1112ae1afd2fSChristopher Smith } 1113ae1afd2fSChristopher Smith } else { 1114ae1afd2fSChristopher Smith msg($this->lang['import_error_readfail'], -1); 1115ae1afd2fSChristopher Smith } 1116ae1afd2fSChristopher Smith 1117ae1afd2fSChristopher Smith // save import failures into the session 1118ae1afd2fSChristopher Smith if (!headers_sent()) { 1119ae1afd2fSChristopher Smith session_start(); 11203a97d936SAndreas Gohr $_SESSION['import_failures'] = $this->import_failures; 1121ae1afd2fSChristopher Smith session_write_close(); 1122ae1afd2fSChristopher Smith } 1123c5a7c0c6SGerrit Uitslag return true; 1124ae1afd2fSChristopher Smith } 1125ae1afd2fSChristopher Smith 1126c5a7c0c6SGerrit Uitslag /** 1127786dfb0eSGerrit Uitslag * Returns cleaned user data 1128c5a7c0c6SGerrit Uitslag * 1129c5a7c0c6SGerrit Uitslag * @param array $candidate raw values of line from input file 1130253d4b48SGerrit Uitslag * @param string $error 1131253d4b48SGerrit Uitslag * @return array|false cleaned data or false 1132c5a7c0c6SGerrit Uitslag */ 11333a97d936SAndreas Gohr protected function cleanImportUser($candidate, & $error) 11343a97d936SAndreas Gohr { 1135ae1afd2fSChristopher Smith global $INPUT; 1136ae1afd2fSChristopher Smith 11373a97d936SAndreas Gohr // FIXME kludgy .... 1138ae1afd2fSChristopher Smith $INPUT->set('userid', $candidate[0]); 1139ae1afd2fSChristopher Smith $INPUT->set('userpass', $candidate[1]); 1140ae1afd2fSChristopher Smith $INPUT->set('username', $candidate[2]); 1141ae1afd2fSChristopher Smith $INPUT->set('usermail', $candidate[3]); 1142ae1afd2fSChristopher Smith $INPUT->set('usergroups', $candidate[4]); 1143ae1afd2fSChristopher Smith 11443a97d936SAndreas Gohr $cleaned = $this->retrieveUser(); 1145*54cc7aa4SAndreas Gohr [$user, /* pass */ , $name, $mail, /* grps */ ] = $cleaned; 1146ae1afd2fSChristopher Smith if (empty($user)) { 1147ae1afd2fSChristopher Smith $error = $this->lang['import_error_baduserid']; 1148ae1afd2fSChristopher Smith return false; 1149ae1afd2fSChristopher Smith } 1150ae1afd2fSChristopher Smith 1151ae1afd2fSChristopher Smith // no need to check password, handled elsewhere 1152ae1afd2fSChristopher Smith 11533a97d936SAndreas Gohr if (!($this->auth->canDo('modName') xor empty($name))) { 1154ae1afd2fSChristopher Smith $error = $this->lang['import_error_badname']; 1155ae1afd2fSChristopher Smith return false; 1156ae1afd2fSChristopher Smith } 1157ae1afd2fSChristopher Smith 11583a97d936SAndreas Gohr if ($this->auth->canDo('modMail')) { 1159328143f8SChristopher Smith if (empty($mail) || !mail_isvalid($mail)) { 1160ae1afd2fSChristopher Smith $error = $this->lang['import_error_badmail']; 1161ae1afd2fSChristopher Smith return false; 1162ae1afd2fSChristopher Smith } 1163*54cc7aa4SAndreas Gohr } elseif (!empty($mail)) { 1164328143f8SChristopher Smith $error = $this->lang['import_error_badmail']; 1165328143f8SChristopher Smith return false; 1166328143f8SChristopher Smith } 1167ae1afd2fSChristopher Smith 1168ae1afd2fSChristopher Smith return $cleaned; 1169ae1afd2fSChristopher Smith } 1170ae1afd2fSChristopher Smith 1171c5a7c0c6SGerrit Uitslag /** 1172c5a7c0c6SGerrit Uitslag * Adds imported user to auth backend 1173c5a7c0c6SGerrit Uitslag * 1174c5a7c0c6SGerrit Uitslag * Required a check of canDo('addUser') before 1175c5a7c0c6SGerrit Uitslag * 1176c5a7c0c6SGerrit Uitslag * @param array $user data of user 1177c5a7c0c6SGerrit Uitslag * @param string &$error reference catched error message 11785ba64050SChristopher Smith * @return bool whether successful 1179c5a7c0c6SGerrit Uitslag */ 11803a97d936SAndreas Gohr protected function importUser($user, &$error) 11813a97d936SAndreas Gohr { 11823a97d936SAndreas Gohr if (!$this->auth->triggerUserMod('create', $user)) { 1183ae1afd2fSChristopher Smith $error = $this->lang['import_error_create']; 1184ae1afd2fSChristopher Smith return false; 1185ae1afd2fSChristopher Smith } 1186ae1afd2fSChristopher Smith 1187ae1afd2fSChristopher Smith return true; 1188ae1afd2fSChristopher Smith } 1189ae1afd2fSChristopher Smith 1190c5a7c0c6SGerrit Uitslag /** 1191c5a7c0c6SGerrit Uitslag * Downloads failures as csv file 1192c5a7c0c6SGerrit Uitslag */ 11933a97d936SAndreas Gohr protected function downloadImportFailures() 11943a97d936SAndreas Gohr { 1195ae1afd2fSChristopher Smith 1196ae1afd2fSChristopher Smith // ============================================================================================== 1197ae1afd2fSChristopher Smith // GENERATE OUTPUT 1198ae1afd2fSChristopher Smith // normal headers for downloading... 1199ae1afd2fSChristopher Smith header('Content-type: text/csv;charset=utf-8'); 1200ae1afd2fSChristopher Smith header('Content-Disposition: attachment; filename="importfails.csv"'); 1201ae1afd2fSChristopher Smith# // for debugging assistance, send as text plain to the browser 1202ae1afd2fSChristopher Smith# header('Content-type: text/plain;charset=utf-8'); 1203ae1afd2fSChristopher Smith 1204ae1afd2fSChristopher Smith // output the csv 1205ae1afd2fSChristopher Smith $fd = fopen('php://output', 'w'); 12063a97d936SAndreas Gohr foreach ($this->import_failures as $fail) { 1207*54cc7aa4SAndreas Gohr fwrite($fd, $fail['orig']); 1208ae1afd2fSChristopher Smith } 1209ae1afd2fSChristopher Smith fclose($fd); 1210ae1afd2fSChristopher Smith die; 1211ae1afd2fSChristopher Smith } 1212ae1afd2fSChristopher Smith 1213b2c01466SChristopher Smith /** 1214b2c01466SChristopher Smith * wrapper for is_uploaded_file to facilitate overriding by test suite 1215253d4b48SGerrit Uitslag * 1216253d4b48SGerrit Uitslag * @param string $file filename 1217253d4b48SGerrit Uitslag * @return bool 1218b2c01466SChristopher Smith */ 12193a97d936SAndreas Gohr protected function isUploadedFile($file) 12203a97d936SAndreas Gohr { 1221b2c01466SChristopher Smith return is_uploaded_file($file); 1222b2c01466SChristopher Smith } 12230440ff15Schris} 1224