10440ff15Schris<?php 254cc7aa4SAndreas Gohr 38553d24dSAndreas Gohruse dokuwiki\Extension\AdminPlugin; 451ee2399SGerrit Uitslaguse dokuwiki\Extension\AuthPlugin; 5*73dc0a89SAndreas Gohruse dokuwiki\MailUtils; 654cc7aa4SAndreas Gohruse dokuwiki\Utf8\Clean; 753c68e5cSAndreas Gohruse dokuwiki\Utf8\Conversion; 8a664aabaSAndreas Gohr 90440ff15Schris/* 100440ff15Schris * User Manager 110440ff15Schris * 120440ff15Schris * Dokuwiki Admin Plugin 130440ff15Schris * 140440ff15Schris * This version of the user manager has been modified to only work with 150440ff15Schris * objectified version of auth system 160440ff15Schris * 170440ff15Schris * @author neolao <neolao@neolao.com> 180440ff15Schris * @author Chris Smith <chris@jalakai.co.uk> 190440ff15Schris */ 20a664aabaSAndreas Gohr 210440ff15Schris/** 220440ff15Schris * All DokuWiki plugins to extend the admin function 230440ff15Schris * need to inherit from this class 240440ff15Schris */ 258553d24dSAndreas Gohrclass admin_plugin_usermanager extends AdminPlugin 263a97d936SAndreas Gohr{ 27bf9be0e3SAndreas Gohr protected const IMAGE_DIR = DOKU_BASE . 'lib/plugins/usermanager/images/'; 280440ff15Schris 2954cc7aa4SAndreas Gohr protected $auth; // auth object 303a97d936SAndreas Gohr protected $users_total = 0; // number of registered users 3154cc7aa4SAndreas Gohr protected $filter = []; // user selection filter(s) 323a97d936SAndreas Gohr protected $start = 0; // index of first user to be displayed 333a97d936SAndreas Gohr protected $last = 0; // index of the last user to be displayed 343a97d936SAndreas Gohr protected $pagesize = 20; // number of users to list on one page 353a97d936SAndreas Gohr protected $edit_user = ''; // set to user selected for editing 3654cc7aa4SAndreas Gohr protected $edit_userdata = []; 373a97d936SAndreas Gohr protected $disabled = ''; // if disabled set to explanatory string 3854cc7aa4SAndreas Gohr protected $import_failures = []; 393a97d936SAndreas Gohr protected $lastdisabled = false; // set to true if last user is unknown and last button is hence buggy 400440ff15Schris 410440ff15Schris /** 420440ff15Schris * Constructor 430440ff15Schris */ 443a97d936SAndreas Gohr public function __construct() 453a97d936SAndreas Gohr { 4651ee2399SGerrit Uitslag /** @var AuthPlugin $auth */ 470440ff15Schris global $auth; 480440ff15Schris 490440ff15Schris $this->setupLocale(); 5051d94d49Schris 516547cfc7SGerrit Uitslag if (!$auth instanceof AuthPlugin) { 523a97d936SAndreas Gohr $this->disabled = $this->lang['noauth']; 5382fd59b6SAndreas Gohr } elseif (!$auth->canDo('getUsers')) { 543a97d936SAndreas Gohr $this->disabled = $this->lang['nosupport']; 5551d94d49Schris } else { 5651d94d49Schris // we're good to go 573a97d936SAndreas Gohr $this->auth = &$auth; 5851d94d49Schris } 59ae1afd2fSChristopher Smith 60ae1afd2fSChristopher Smith // attempt to retrieve any import failures from the session 610e80bb5eSChristopher Smith if (!empty($_SESSION['import_failures'])) { 623a97d936SAndreas Gohr $this->import_failures = $_SESSION['import_failures']; 63ae1afd2fSChristopher Smith } 640440ff15Schris } 650440ff15Schris 660440ff15Schris /** 67c5a7c0c6SGerrit Uitslag * Return prompt for admin menu 68253d4b48SGerrit Uitslag * 69253d4b48SGerrit Uitslag * @param string $language 70253d4b48SGerrit Uitslag * @return string 710440ff15Schris */ 723a97d936SAndreas Gohr public function getMenuText($language) 733a97d936SAndreas Gohr { 740440ff15Schris 753a97d936SAndreas Gohr if (!is_null($this->auth)) 760440ff15Schris return parent::getMenuText($language); 770440ff15Schris 783a97d936SAndreas Gohr return $this->getLang('menu') . ' ' . $this->disabled; 790440ff15Schris } 800440ff15Schris 810440ff15Schris /** 820440ff15Schris * return sort order for position in admin menu 83253d4b48SGerrit Uitslag * 84253d4b48SGerrit Uitslag * @return int 850440ff15Schris */ 863a97d936SAndreas Gohr public function getMenuSort() 873a97d936SAndreas Gohr { 880440ff15Schris return 2; 890440ff15Schris } 900440ff15Schris 910440ff15Schris /** 9267a31a83SMichael Große * @return int current start value for pageination 9367a31a83SMichael Große */ 943a97d936SAndreas Gohr public function getStart() 953a97d936SAndreas Gohr { 963a97d936SAndreas Gohr return $this->start; 9767a31a83SMichael Große } 9867a31a83SMichael Große 9967a31a83SMichael Große /** 10067a31a83SMichael Große * @return int number of users per page 10167a31a83SMichael Große */ 1023a97d936SAndreas Gohr public function getPagesize() 1033a97d936SAndreas Gohr { 1043a97d936SAndreas Gohr return $this->pagesize; 10567a31a83SMichael Große } 10667a31a83SMichael Große 10767a31a83SMichael Große /** 108462e9e37SMichael Große * @param boolean $lastdisabled 109462e9e37SMichael Große */ 1103a97d936SAndreas Gohr public function setLastdisabled($lastdisabled) 1113a97d936SAndreas Gohr { 1123a97d936SAndreas Gohr $this->lastdisabled = $lastdisabled; 113462e9e37SMichael Große } 114462e9e37SMichael Große 115462e9e37SMichael Große /** 116c5a7c0c6SGerrit Uitslag * Handle user request 117253d4b48SGerrit Uitslag * 118253d4b48SGerrit Uitslag * @return bool 1190440ff15Schris */ 1203a97d936SAndreas Gohr public function handle() 1213a97d936SAndreas Gohr { 12200d58927SMichael Hamann global $INPUT; 1233a97d936SAndreas Gohr if (is_null($this->auth)) return false; 1240440ff15Schris 1250440ff15Schris // extract the command and any specific parameters 1260440ff15Schris // submit button name is of the form - fn[cmd][param(s)] 12700d58927SMichael Hamann $fn = $INPUT->param('fn'); 1280440ff15Schris 1290440ff15Schris if (is_array($fn)) { 1300440ff15Schris $cmd = key($fn); 1310440ff15Schris $param = is_array($fn[$cmd]) ? key($fn[$cmd]) : null; 1320440ff15Schris } else { 1330440ff15Schris $cmd = $fn; 1340440ff15Schris $param = null; 1350440ff15Schris } 1360440ff15Schris 1370440ff15Schris if ($cmd != "search") { 1383a97d936SAndreas Gohr $this->start = $INPUT->int('start', 0); 1393a97d936SAndreas Gohr $this->filter = $this->retrieveFilter(); 1400440ff15Schris } 1410440ff15Schris 1420440ff15Schris switch ($cmd) { 1433a97d936SAndreas Gohr case "add": 1443a97d936SAndreas Gohr $this->addUser(); 1450440ff15Schris break; 1463a97d936SAndreas Gohr case "delete": 1473a97d936SAndreas Gohr $this->deleteUser(); 1483a97d936SAndreas Gohr break; 1493a97d936SAndreas Gohr case "modify": 1503a97d936SAndreas Gohr $this->modifyUser(); 1513a97d936SAndreas Gohr break; 1523a97d936SAndreas Gohr case "edit": 1533a97d936SAndreas Gohr $this->editUser($param); 1543a97d936SAndreas Gohr break; 1553a97d936SAndreas Gohr case "search": 1563a97d936SAndreas Gohr $this->setFilter($param); 1573a97d936SAndreas Gohr $this->start = 0; 1583a97d936SAndreas Gohr break; 1593a97d936SAndreas Gohr case "export": 1603a97d936SAndreas Gohr $this->exportCSV(); 1613a97d936SAndreas Gohr break; 1623a97d936SAndreas Gohr case "import": 1633a97d936SAndreas Gohr $this->importCSV(); 1643a97d936SAndreas Gohr break; 1653a97d936SAndreas Gohr case "importfails": 1663a97d936SAndreas Gohr $this->downloadImportFailures(); 1673a97d936SAndreas Gohr break; 1680440ff15Schris } 1690440ff15Schris 1703a97d936SAndreas Gohr $this->users_total = $this->auth->canDo('getUserCount') ? $this->auth->getUserCount($this->filter) : -1; 1710440ff15Schris 1720440ff15Schris // page handling 1730440ff15Schris switch ($cmd) { 1743a97d936SAndreas Gohr case 'start': 1753a97d936SAndreas Gohr $this->start = 0; 1763a97d936SAndreas Gohr break; 1773a97d936SAndreas Gohr case 'prev': 1783a97d936SAndreas Gohr $this->start -= $this->pagesize; 1793a97d936SAndreas Gohr break; 1803a97d936SAndreas Gohr case 'next': 1813a97d936SAndreas Gohr $this->start += $this->pagesize; 1823a97d936SAndreas Gohr break; 1833a97d936SAndreas Gohr case 'last': 1843a97d936SAndreas Gohr $this->start = $this->users_total; 1853a97d936SAndreas Gohr break; 1860440ff15Schris } 1873a97d936SAndreas Gohr $this->validatePagination(); 188c5a7c0c6SGerrit Uitslag return true; 1890440ff15Schris } 1900440ff15Schris 1910440ff15Schris /** 192c5a7c0c6SGerrit Uitslag * Output appropriate html 193253d4b48SGerrit Uitslag * 194253d4b48SGerrit Uitslag * @return bool 195a664aabaSAndreas Gohr * @todo split into smaller functions, use Form class 1960440ff15Schris */ 1973a97d936SAndreas Gohr public function html() 1983a97d936SAndreas Gohr { 1990440ff15Schris global $ID; 2000440ff15Schris 2013a97d936SAndreas Gohr if (is_null($this->auth)) { 20226dfc232SAndreas Gohr echo $this->lang['badauth']; 2030440ff15Schris return false; 2040440ff15Schris } 2050440ff15Schris 2063a97d936SAndreas Gohr $user_list = $this->auth->retrieveUsers($this->start, $this->pagesize, $this->filter); 2070440ff15Schris 2083a97d936SAndreas Gohr $page_buttons = $this->pagination(); 2093a97d936SAndreas Gohr $delete_disable = $this->auth->canDo('delUser') ? '' : 'disabled="disabled"'; 2100440ff15Schris 2113a97d936SAndreas Gohr $editable = $this->auth->canDo('UserMod'); 2123a97d936SAndreas Gohr $export_label = empty($this->filter) ? $this->lang['export_all'] : $this->lang['export_filtered']; 2136154103cSmatthiasgrimm 21426dfc232SAndreas Gohr echo $this->locale_xhtml('intro'); 21526dfc232SAndreas Gohr echo $this->locale_xhtml('list'); 2160440ff15Schris 217a664aabaSAndreas Gohr echo '<div id="user__manager">'; 218a664aabaSAndreas Gohr echo '<div class="level2">'; 2190440ff15Schris 2203a97d936SAndreas Gohr if ($this->users_total > 0) { 221a664aabaSAndreas Gohr printf( 222a664aabaSAndreas Gohr '<p>' . $this->lang['summary'] . '</p>', 2233a97d936SAndreas Gohr $this->start + 1, 2243a97d936SAndreas Gohr $this->last, 2253a97d936SAndreas Gohr $this->users_total, 2263a97d936SAndreas Gohr $this->auth->getUserCount() 22764159a61SAndreas Gohr ); 2280440ff15Schris } else { 2293a97d936SAndreas Gohr if ($this->users_total < 0) { 230a102b175SGerrit Uitslag $allUserTotal = 0; 231a102b175SGerrit Uitslag } else { 2323a97d936SAndreas Gohr $allUserTotal = $this->auth->getUserCount(); 233a102b175SGerrit Uitslag } 234a664aabaSAndreas Gohr printf('<p>%s</p>', sprintf($this->lang['nonefound'], $allUserTotal)); 2350440ff15Schris } 236a664aabaSAndreas Gohr printf('<form action="%s" method="post">', wl($ID)); 237634d7150SAndreas Gohr formSecurityToken(); 238a664aabaSAndreas Gohr echo '<div class="table">'; 239a664aabaSAndreas Gohr echo '<table class="inline">'; 240a664aabaSAndreas Gohr echo '<thead>'; 241a664aabaSAndreas Gohr echo '<tr>'; 242a664aabaSAndreas Gohr echo '<th> </th>'; 243a664aabaSAndreas Gohr echo '<th>' . $this->lang["user_id"] . '</th>'; 244a664aabaSAndreas Gohr echo '<th>' . $this->lang["user_name"] . '</th>'; 245a664aabaSAndreas Gohr echo '<th>' . $this->lang["user_mail"] . '</th>'; 246a664aabaSAndreas Gohr echo '<th>' . $this->lang["user_groups"] . '</th>'; 247a664aabaSAndreas Gohr echo '</tr>'; 2480440ff15Schris 249a664aabaSAndreas Gohr echo '<tr>'; 250a664aabaSAndreas Gohr echo '<td class="rightalign"><input type="image" src="' . 251a664aabaSAndreas Gohr self::IMAGE_DIR . 'search.png" name="fn[search][new]" title="' . 252a664aabaSAndreas Gohr $this->lang['search_prompt'] . '" alt="' . $this->lang['search'] . '" class="button" /></td>'; 253a664aabaSAndreas Gohr echo '<td><input type="text" name="userid" class="edit" value="' . $this->htmlFilter('user') . '" /></td>'; 254a664aabaSAndreas Gohr echo '<td><input type="text" name="username" class="edit" value="' . $this->htmlFilter('name') . '" /></td>'; 255a664aabaSAndreas Gohr echo '<td><input type="text" name="usermail" class="edit" value="' . $this->htmlFilter('mail') . '" /></td>'; 256a664aabaSAndreas Gohr echo '<td><input type="text" name="usergroups" class="edit" value="' . $this->htmlFilter('grps') . '" /></td>'; 257a664aabaSAndreas Gohr echo '</tr>'; 258a664aabaSAndreas Gohr echo '</thead>'; 2590440ff15Schris 2603a97d936SAndreas Gohr if ($this->users_total) { 261a664aabaSAndreas Gohr echo '<tbody>'; 2620440ff15Schris foreach ($user_list as $user => $userinfo) { 2630440ff15Schris extract($userinfo); 264c5a7c0c6SGerrit Uitslag /** 265c5a7c0c6SGerrit Uitslag * @var string $name 266c5a7c0c6SGerrit Uitslag * @var string $pass 267c5a7c0c6SGerrit Uitslag * @var string $mail 268c5a7c0c6SGerrit Uitslag * @var array $grps 269c5a7c0c6SGerrit Uitslag */ 27054cc7aa4SAndreas Gohr $groups = implode(', ', $grps); 271a664aabaSAndreas Gohr echo '<tr class="user_info">'; 272a664aabaSAndreas Gohr echo '<td class="centeralign"><input type="checkbox" name="delete[' . hsc($user) . 273a664aabaSAndreas Gohr ']" ' . $delete_disable . ' /></td>'; 2742365d73dSAnika Henke if ($editable) { 275a664aabaSAndreas Gohr echo '<td><a href="' . wl($ID, ['fn[edit][' . $user . ']' => 1, 27677d19185SAndreas Gohr 'do' => 'admin', 27777d19185SAndreas Gohr 'page' => 'usermanager', 27854cc7aa4SAndreas Gohr 'sectok' => getSecurityToken()]) . 279a664aabaSAndreas Gohr '" title="' . $this->lang['edit_prompt'] . '">' . hsc($user) . '</a></td>'; 2802365d73dSAnika Henke } else { 281a664aabaSAndreas Gohr echo '<td>' . hsc($user) . '</td>'; 2822365d73dSAnika Henke } 283a664aabaSAndreas Gohr echo '<td>' . hsc($name) . '</td><td>' . hsc($mail) . '</td><td>' . hsc($groups) . '</td>'; 284a664aabaSAndreas Gohr echo '</tr>'; 2850440ff15Schris } 286a664aabaSAndreas Gohr echo '</tbody>'; 2870440ff15Schris } 2880440ff15Schris 289a664aabaSAndreas Gohr echo '<tbody>'; 290a664aabaSAndreas Gohr echo '<tr><td colspan="5" class="centeralign">'; 291a664aabaSAndreas Gohr echo '<span class="medialeft">'; 292a664aabaSAndreas Gohr echo '<button type="submit" name="fn[delete]" id="usrmgr__del" ' . $delete_disable . '>' . 293a664aabaSAndreas Gohr $this->lang['delete_selected'] . '</button>'; 294a664aabaSAndreas Gohr echo '</span>'; 295a664aabaSAndreas Gohr echo '<span class="mediaright">'; 296a664aabaSAndreas Gohr echo '<button type="submit" name="fn[start]" ' . $page_buttons['start'] . '>' . 297a664aabaSAndreas Gohr $this->lang['start'] . '</button>'; 298a664aabaSAndreas Gohr echo '<button type="submit" name="fn[prev]" ' . $page_buttons['prev'] . '>' . 299a664aabaSAndreas Gohr $this->lang['prev'] . "</button>"; 300a664aabaSAndreas Gohr echo '<button type="submit" name="fn[next]" ' . $page_buttons['next'] . '>' . 301a664aabaSAndreas Gohr $this->lang['next'] . '</button>'; 302a664aabaSAndreas Gohr echo '<button type="submit" name="fn[last]" ' . $page_buttons['last'] . '>' . 303a664aabaSAndreas Gohr $this->lang['last'] . '</button>'; 304a664aabaSAndreas Gohr echo '</span>'; 3053a97d936SAndreas Gohr if (!empty($this->filter)) { 306a664aabaSAndreas Gohr echo '<button type="submit" name="fn[search][clear]">' . $this->lang['clear'] . '</button>'; 3075c967d3dSChristopher Smith } 308a664aabaSAndreas Gohr echo '<button type="submit" name="fn[export]">' . $export_label . '</button>'; 309a664aabaSAndreas Gohr echo '<input type="hidden" name="do" value="admin" />'; 310a664aabaSAndreas Gohr echo '<input type="hidden" name="page" value="usermanager" />'; 311daf4ca4eSAnika Henke 3123a97d936SAndreas Gohr $this->htmlFilterSettings(2); 313daf4ca4eSAnika Henke 314a664aabaSAndreas Gohr echo '</td></tr>'; 315a664aabaSAndreas Gohr echo '</tbody>'; 316a664aabaSAndreas Gohr echo '</table>'; 317a664aabaSAndreas Gohr echo '</div>'; 3180440ff15Schris 319a664aabaSAndreas Gohr echo '</form>'; 320a664aabaSAndreas Gohr echo '</div>'; 3210440ff15Schris 322a664aabaSAndreas Gohr $style = $this->edit_user ? ' class="edit_user"' : ''; 3230440ff15Schris 3243a97d936SAndreas Gohr if ($this->auth->canDo('addUser')) { 325a664aabaSAndreas Gohr echo '<div' . $style . '>'; 32626dfc232SAndreas Gohr echo $this->locale_xhtml('add'); 327a664aabaSAndreas Gohr echo '<div class="level2">'; 3280440ff15Schris 32954cc7aa4SAndreas Gohr $this->htmlUserForm('add', null, [], 4); 3300440ff15Schris 331a664aabaSAndreas Gohr echo '</div>'; 332a664aabaSAndreas Gohr echo '</div>'; 3330440ff15Schris } 3340440ff15Schris 3353a97d936SAndreas Gohr if ($this->edit_user && $this->auth->canDo('UserMod')) { 336a664aabaSAndreas Gohr echo '<div' . $style . ' id="scroll__here">'; 33726dfc232SAndreas Gohr echo $this->locale_xhtml('edit'); 338a664aabaSAndreas Gohr echo '<div class="level2">'; 3390440ff15Schris 3403a97d936SAndreas Gohr $this->htmlUserForm('modify', $this->edit_user, $this->edit_userdata, 4); 3410440ff15Schris 342a664aabaSAndreas Gohr echo '</div>'; 343a664aabaSAndreas Gohr echo '</div>'; 3440440ff15Schris } 345ae1afd2fSChristopher Smith 3463a97d936SAndreas Gohr if ($this->auth->canDo('addUser')) { 3473a97d936SAndreas Gohr $this->htmlImportForm(); 348ae1afd2fSChristopher Smith } 349a664aabaSAndreas Gohr echo '</div>'; 350c5a7c0c6SGerrit Uitslag return true; 3510440ff15Schris } 3520440ff15Schris 35382fd59b6SAndreas Gohr /** 35464cdf779SAndreas Gohr * User Manager is only available if the auth backend supports it 35564cdf779SAndreas Gohr * 35664cdf779SAndreas Gohr * @inheritdoc 35764cdf779SAndreas Gohr * @return bool 35864cdf779SAndreas Gohr */ 35964cdf779SAndreas Gohr public function isAccessibleByCurrentUser() 36064cdf779SAndreas Gohr { 36151ee2399SGerrit Uitslag /** @var AuthPlugin $auth */ 36264cdf779SAndreas Gohr global $auth; 3636547cfc7SGerrit Uitslag if (!$auth instanceof AuthPlugin || !$auth->canDo('getUsers')) { 36464cdf779SAndreas Gohr return false; 36564cdf779SAndreas Gohr } 36664cdf779SAndreas Gohr 36764cdf779SAndreas Gohr return parent::isAccessibleByCurrentUser(); 36864cdf779SAndreas Gohr } 36964cdf779SAndreas Gohr 37064cdf779SAndreas Gohr 37164cdf779SAndreas Gohr /** 372c5a7c0c6SGerrit Uitslag * Display form to add or modify a user 373c5a7c0c6SGerrit Uitslag * 374c5a7c0c6SGerrit Uitslag * @param string $cmd 'add' or 'modify' 375c5a7c0c6SGerrit Uitslag * @param string $user id of user 376c5a7c0c6SGerrit Uitslag * @param array $userdata array with name, mail, pass and grps 377c5a7c0c6SGerrit Uitslag * @param int $indent 378a664aabaSAndreas Gohr * @todo use Form class 37982fd59b6SAndreas Gohr */ 38054cc7aa4SAndreas Gohr protected function htmlUserForm($cmd, $user = '', $userdata = [], $indent = 0) 3813a97d936SAndreas Gohr { 382a6858c6aSchris global $conf; 383bb4866bdSchris global $ID; 384be9008d3SChristopher Smith global $lang; 38554cc7aa4SAndreas Gohr $name = ''; 38654cc7aa4SAndreas Gohr $mail = ''; 38754cc7aa4SAndreas Gohr $groups = ''; 38854cc7aa4SAndreas Gohr $notes = []; 3890440ff15Schris 3900440ff15Schris if ($user) { 39178c7c8c9Schris extract($userdata); 39254cc7aa4SAndreas Gohr if (!empty($grps)) $groups = implode(',', $grps); 393a6858c6aSchris } else { 394a6858c6aSchris $notes[] = sprintf($this->lang['note_group'], $conf['defaultgroup']); 3950440ff15Schris } 3960440ff15Schris 397a664aabaSAndreas Gohr printf('<form action="%s" method="post">', wl($ID)); 398634d7150SAndreas Gohr formSecurityToken(); 399a664aabaSAndreas Gohr echo '<div class="table">'; 400a664aabaSAndreas Gohr echo '<table class="inline">'; 401a664aabaSAndreas Gohr echo '<thead>'; 402a664aabaSAndreas Gohr echo '<tr><th>' . $this->lang["field"] . "</th><th>" . $this->lang["value"] . "</th></tr>"; 403a664aabaSAndreas Gohr echo '</thead>'; 404a664aabaSAndreas Gohr echo '<tbody>'; 40526fb387bSchris 4063a97d936SAndreas Gohr $this->htmlInputField( 40764159a61SAndreas Gohr $cmd . "_userid", 40864159a61SAndreas Gohr "userid", 40964159a61SAndreas Gohr $this->lang["user_id"], 41064159a61SAndreas Gohr $user, 4113a97d936SAndreas Gohr $this->auth->canDo("modLogin"), 41264159a61SAndreas Gohr true, 41364159a61SAndreas Gohr $indent + 6 41464159a61SAndreas Gohr ); 4153a97d936SAndreas Gohr $this->htmlInputField( 41664159a61SAndreas Gohr $cmd . "_userpass", 41764159a61SAndreas Gohr "userpass", 41864159a61SAndreas Gohr $this->lang["user_pass"], 41964159a61SAndreas Gohr "", 4203a97d936SAndreas Gohr $this->auth->canDo("modPass"), 42164159a61SAndreas Gohr false, 42264159a61SAndreas Gohr $indent + 6 42364159a61SAndreas Gohr ); 4243a97d936SAndreas Gohr $this->htmlInputField( 42564159a61SAndreas Gohr $cmd . "_userpass2", 42664159a61SAndreas Gohr "userpass2", 42764159a61SAndreas Gohr $lang["passchk"], 42864159a61SAndreas Gohr "", 4293a97d936SAndreas Gohr $this->auth->canDo("modPass"), 43064159a61SAndreas Gohr false, 43164159a61SAndreas Gohr $indent + 6 43264159a61SAndreas Gohr ); 4333a97d936SAndreas Gohr $this->htmlInputField( 43464159a61SAndreas Gohr $cmd . "_username", 43564159a61SAndreas Gohr "username", 43664159a61SAndreas Gohr $this->lang["user_name"], 43764159a61SAndreas Gohr $name, 4383a97d936SAndreas Gohr $this->auth->canDo("modName"), 43964159a61SAndreas Gohr true, 44064159a61SAndreas Gohr $indent + 6 44164159a61SAndreas Gohr ); 4423a97d936SAndreas Gohr $this->htmlInputField( 44364159a61SAndreas Gohr $cmd . "_usermail", 44464159a61SAndreas Gohr "usermail", 44564159a61SAndreas Gohr $this->lang["user_mail"], 44664159a61SAndreas Gohr $mail, 4473a97d936SAndreas Gohr $this->auth->canDo("modMail"), 44864159a61SAndreas Gohr true, 44964159a61SAndreas Gohr $indent + 6 45064159a61SAndreas Gohr ); 4513a97d936SAndreas Gohr $this->htmlInputField( 45264159a61SAndreas Gohr $cmd . "_usergroups", 45364159a61SAndreas Gohr "usergroups", 45464159a61SAndreas Gohr $this->lang["user_groups"], 45564159a61SAndreas Gohr $groups, 4563a97d936SAndreas Gohr $this->auth->canDo("modGroups"), 45764159a61SAndreas Gohr false, 45864159a61SAndreas Gohr $indent + 6 45964159a61SAndreas Gohr ); 46026fb387bSchris 4613a97d936SAndreas Gohr if ($this->auth->canDo("modPass")) { 462ee9498f5SChristopher Smith if ($cmd == 'add') { 463c3f4fb63SGina Haeussge $notes[] = $this->lang['note_pass']; 464ee9498f5SChristopher Smith } 465a6858c6aSchris if ($user) { 466a6858c6aSchris $notes[] = $this->lang['note_notify']; 467a6858c6aSchris } 468a6858c6aSchris 469a664aabaSAndreas Gohr echo '<tr><td><label for="' . $cmd . "_usernotify\" >" . 470a664aabaSAndreas Gohr $this->lang["user_notify"] . ': </label></td> 471a664aabaSAndreas Gohr <td><input type="checkbox" id="' . $cmd . '_usernotify" name="usernotify" value="1" /> 472a664aabaSAndreas Gohr </td></tr>'; 473a6858c6aSchris } 474a6858c6aSchris 475a664aabaSAndreas Gohr echo '</tbody>'; 476a664aabaSAndreas Gohr echo '<tbody>'; 477a664aabaSAndreas Gohr echo '<tr>'; 478a664aabaSAndreas Gohr echo '<td colspan="2">'; 479a664aabaSAndreas Gohr echo '<input type="hidden" name="do" value="admin" />'; 480a664aabaSAndreas Gohr echo '<input type="hidden" name="page" value="usermanager" />'; 4810440ff15Schris 4820440ff15Schris // save current $user, we need this to access details if the name is changed 483a664aabaSAndreas Gohr if ($user) { 484a664aabaSAndreas Gohr echo '<input type="hidden" name="userid_old" value="' . hsc($user) . "\" />"; 485a664aabaSAndreas Gohr } 4860440ff15Schris 4873a97d936SAndreas Gohr $this->htmlFilterSettings($indent + 10); 4880440ff15Schris 489a664aabaSAndreas Gohr echo '<button type="submit" name="fn[' . $cmd . ']">' . $this->lang[$cmd] . '</button>'; 490a664aabaSAndreas Gohr echo '</td>'; 491a664aabaSAndreas Gohr echo '</tr>'; 492a664aabaSAndreas Gohr echo '</tbody>'; 493a664aabaSAndreas Gohr echo '</table>'; 49445c19902SChristopher Smith 49545c19902SChristopher Smith if ($notes) { 496a664aabaSAndreas Gohr echo '<ul class="notes">'; 49745c19902SChristopher Smith foreach ($notes as $note) { 498a664aabaSAndreas Gohr echo '<li><span class="li">' . $note . '</li>'; 49945c19902SChristopher Smith } 500a664aabaSAndreas Gohr echo '</ul>'; 50145c19902SChristopher Smith } 502a664aabaSAndreas Gohr echo '</div>'; 503a664aabaSAndreas Gohr echo '</form>'; 5040440ff15Schris } 5050440ff15Schris 506c5a7c0c6SGerrit Uitslag /** 507c5a7c0c6SGerrit Uitslag * Prints a inputfield 508c5a7c0c6SGerrit Uitslag * 509c5a7c0c6SGerrit Uitslag * @param string $id 510c5a7c0c6SGerrit Uitslag * @param string $name 511c5a7c0c6SGerrit Uitslag * @param string $label 512c5a7c0c6SGerrit Uitslag * @param string $value 513c5a7c0c6SGerrit Uitslag * @param bool $cando whether auth backend is capable to do this action 5149b82d43fSAndreas Gohr * @param bool $required is this field required? 515c5a7c0c6SGerrit Uitslag * @param int $indent 516a664aabaSAndreas Gohr * @todo obsolete when Form class is used 517c5a7c0c6SGerrit Uitslag */ 5183a97d936SAndreas Gohr protected function htmlInputField($id, $name, $label, $value, $cando, $required, $indent = 0) 5193a97d936SAndreas Gohr { 5207de12fceSAndreas Gohr $class = $cando ? '' : ' class="disabled"'; 5217de12fceSAndreas Gohr echo str_pad('', $indent); 5227de12fceSAndreas Gohr 523359e9417SChristopher Smith if ($name == 'userpass' || $name == 'userpass2') { 524d796a891SAndreas Gohr $fieldtype = 'password'; 525d796a891SAndreas Gohr $autocomp = 'autocomplete="off"'; 5267b3674bdSChristopher Smith } elseif ($name == 'usermail') { 5277b3674bdSChristopher Smith $fieldtype = 'email'; 5287b3674bdSChristopher Smith $autocomp = ''; 529d796a891SAndreas Gohr } else { 530d796a891SAndreas Gohr $fieldtype = 'text'; 531d796a891SAndreas Gohr $autocomp = ''; 532d796a891SAndreas Gohr } 533f23f9594SAndreas Gohr $value = hsc($value); 534d796a891SAndreas Gohr 5357de12fceSAndreas Gohr echo "<tr $class>"; 5367de12fceSAndreas Gohr echo "<td><label for=\"$id\" >$label: </label></td>"; 537a664aabaSAndreas Gohr echo '<td>'; 5387de12fceSAndreas Gohr if ($cando) { 5399b82d43fSAndreas Gohr $req = ''; 5409b82d43fSAndreas Gohr if ($required) $req = 'required="required"'; 54164159a61SAndreas Gohr echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\" 54264159a61SAndreas Gohr value=\"$value\" class=\"edit\" $autocomp $req />"; 5437de12fceSAndreas Gohr } else { 5447de12fceSAndreas Gohr echo "<input type=\"hidden\" name=\"$name\" value=\"$value\" />"; 54564159a61SAndreas Gohr echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\" 54664159a61SAndreas Gohr value=\"$value\" class=\"edit disabled\" disabled=\"disabled\" />"; 5477de12fceSAndreas Gohr } 548a664aabaSAndreas Gohr echo '</td>'; 549a664aabaSAndreas Gohr echo '</tr>'; 55026fb387bSchris } 55126fb387bSchris 552c5a7c0c6SGerrit Uitslag /** 553c5a7c0c6SGerrit Uitslag * Returns htmlescaped filter value 554c5a7c0c6SGerrit Uitslag * 555c5a7c0c6SGerrit Uitslag * @param string $key name of search field 556c5a7c0c6SGerrit Uitslag * @return string html escaped value 557c5a7c0c6SGerrit Uitslag */ 5583a97d936SAndreas Gohr protected function htmlFilter($key) 5593a97d936SAndreas Gohr { 5603a97d936SAndreas Gohr if (empty($this->filter)) return ''; 5613a97d936SAndreas Gohr return (isset($this->filter[$key]) ? hsc($this->filter[$key]) : ''); 5620440ff15Schris } 5630440ff15Schris 564c5a7c0c6SGerrit Uitslag /** 565c5a7c0c6SGerrit Uitslag * Print hidden inputs with the current filter values 566c5a7c0c6SGerrit Uitslag * 567c5a7c0c6SGerrit Uitslag * @param int $indent 568c5a7c0c6SGerrit Uitslag */ 5693a97d936SAndreas Gohr protected function htmlFilterSettings($indent = 0) 5703a97d936SAndreas Gohr { 5710440ff15Schris 572a664aabaSAndreas Gohr echo '<input type="hidden" name="start" value="' . $this->start . '" />'; 5730440ff15Schris 5743a97d936SAndreas Gohr foreach ($this->filter as $key => $filter) { 575a664aabaSAndreas Gohr echo '<input type="hidden" name="filter[' . $key . ']" value="' . hsc($filter) . '" />'; 5760440ff15Schris } 5770440ff15Schris } 5780440ff15Schris 579c5a7c0c6SGerrit Uitslag /** 580c5a7c0c6SGerrit Uitslag * Print import form and summary of previous import 581c5a7c0c6SGerrit Uitslag * 582c5a7c0c6SGerrit Uitslag * @param int $indent 583c5a7c0c6SGerrit Uitslag */ 5843a97d936SAndreas Gohr protected function htmlImportForm($indent = 0) 5853a97d936SAndreas Gohr { 586ae1afd2fSChristopher Smith global $ID; 587ae1afd2fSChristopher Smith 58854cc7aa4SAndreas Gohr $failure_download_link = wl($ID, ['do' => 'admin', 'page' => 'usermanager', 'fn[importfails]' => 1]); 589ae1afd2fSChristopher Smith 590a664aabaSAndreas Gohr echo '<div class="level2 import_users">'; 59126dfc232SAndreas Gohr echo $this->locale_xhtml('import'); 592a664aabaSAndreas Gohr echo '<form action="' . wl($ID) . '" method="post" enctype="multipart/form-data">'; 593ae1afd2fSChristopher Smith formSecurityToken(); 594a664aabaSAndreas Gohr echo '<label>' . $this->lang['import_userlistcsv'] . '<input type="file" name="import" /></label>'; 595a664aabaSAndreas Gohr echo '<button type="submit" name="fn[import]">' . $this->lang['import'] . '</button>'; 596a664aabaSAndreas Gohr echo '<input type="hidden" name="do" value="admin" />'; 597a664aabaSAndreas Gohr echo '<input type="hidden" name="page" value="usermanager" />'; 598ae1afd2fSChristopher Smith 5993a97d936SAndreas Gohr $this->htmlFilterSettings($indent + 4); 600a664aabaSAndreas Gohr echo '</form>'; 601a664aabaSAndreas Gohr echo '</div>'; 602ae1afd2fSChristopher Smith 603ae1afd2fSChristopher Smith // list failures from the previous import 6043a97d936SAndreas Gohr if ($this->import_failures) { 6053a97d936SAndreas Gohr $digits = strlen(count($this->import_failures)); 606a664aabaSAndreas Gohr echo '<div class="level3 import_failures">'; 607a664aabaSAndreas Gohr echo '<h3>' . $this->lang['import_header'] . '</h3>'; 608a664aabaSAndreas Gohr echo '<table class="import_failures">'; 609a664aabaSAndreas Gohr echo '<thead>'; 610a664aabaSAndreas Gohr echo '<tr>'; 611a664aabaSAndreas Gohr echo '<th class="line">' . $this->lang['line'] . '</th>'; 612a664aabaSAndreas Gohr echo '<th class="error">' . $this->lang['error'] . '</th>'; 613a664aabaSAndreas Gohr echo '<th class="userid">' . $this->lang['user_id'] . '</th>'; 614a664aabaSAndreas Gohr echo '<th class="username">' . $this->lang['user_name'] . '</th>'; 615a664aabaSAndreas Gohr echo '<th class="usermail">' . $this->lang['user_mail'] . '</th>'; 616a664aabaSAndreas Gohr echo '<th class="usergroups">' . $this->lang['user_groups'] . '</th>'; 617a664aabaSAndreas Gohr echo '</tr>'; 618a664aabaSAndreas Gohr echo '</thead>'; 619a664aabaSAndreas Gohr echo '<tbody>'; 6203a97d936SAndreas Gohr foreach ($this->import_failures as $line => $failure) { 621a664aabaSAndreas Gohr echo '<tr>'; 622a664aabaSAndreas Gohr echo '<td class="lineno"> ' . sprintf('%0' . $digits . 'd', $line) . ' </td>'; 623a664aabaSAndreas Gohr echo '<td class="error">' . $failure['error'] . ' </td>'; 624a664aabaSAndreas Gohr echo '<td class="field userid"> ' . hsc($failure['user'][0]) . ' </td>'; 625a664aabaSAndreas Gohr echo '<td class="field username"> ' . hsc($failure['user'][2]) . ' </td>'; 626a664aabaSAndreas Gohr echo '<td class="field usermail"> ' . hsc($failure['user'][3]) . ' </td>'; 627a664aabaSAndreas Gohr echo '<td class="field usergroups"> ' . hsc($failure['user'][4]) . ' </td>'; 628a664aabaSAndreas Gohr echo '</tr>'; 629ae1afd2fSChristopher Smith } 630a664aabaSAndreas Gohr echo '</tbody>'; 631a664aabaSAndreas Gohr echo '</table>'; 632a664aabaSAndreas Gohr echo '<p><a href="' . $failure_download_link . '">' . $this->lang['import_downloadfailures'] . '</a></p>'; 633a664aabaSAndreas Gohr echo '</div>'; 634ae1afd2fSChristopher Smith } 635ae1afd2fSChristopher Smith } 636ae1afd2fSChristopher Smith 637c5a7c0c6SGerrit Uitslag /** 638c5a7c0c6SGerrit Uitslag * Add an user to auth backend 639c5a7c0c6SGerrit Uitslag * 640c5a7c0c6SGerrit Uitslag * @return bool whether succesful 641c5a7c0c6SGerrit Uitslag */ 6423a97d936SAndreas Gohr protected function addUser() 6433a97d936SAndreas Gohr { 64400d58927SMichael Hamann global $INPUT; 645634d7150SAndreas Gohr if (!checkSecurityToken()) return false; 6463a97d936SAndreas Gohr if (!$this->auth->canDo('addUser')) return false; 6470440ff15Schris 64854cc7aa4SAndreas Gohr [$user, $pass, $name, $mail, $grps, $passconfirm] = $this->retrieveUser(); 6490440ff15Schris if (empty($user)) return false; 6506733c4d7SChris Smith 6513a97d936SAndreas Gohr if ($this->auth->canDo('modPass')) { 652c3f4fb63SGina Haeussge if (empty($pass)) { 65300d58927SMichael Hamann if ($INPUT->has('usernotify')) { 6548a285f7fSAndreas Gohr $pass = auth_pwgen($user); 655c3f4fb63SGina Haeussge } else { 65660b9901bSAndreas Gohr msg($this->lang['add_fail'], -1); 65709a5dcd6SMichael Große msg($this->lang['addUser_error_missing_pass'], -1); 65860b9901bSAndreas Gohr return false; 65960b9901bSAndreas Gohr } 66054cc7aa4SAndreas Gohr } elseif (!$this->verifyPassword($pass, $passconfirm)) { 66109a5dcd6SMichael Große msg($this->lang['add_fail'], -1); 66209a5dcd6SMichael Große msg($this->lang['addUser_error_pass_not_identical'], -1); 663359e9417SChristopher Smith return false; 664359e9417SChristopher Smith } 66554cc7aa4SAndreas Gohr } elseif (!empty($pass)) { 6666733c4d7SChris Smith msg($this->lang['add_fail'], -1); 66709a5dcd6SMichael Große msg($this->lang['addUser_error_modPass_disabled'], -1); 6686733c4d7SChris Smith return false; 6696733c4d7SChris Smith } 6706733c4d7SChris Smith 6713a97d936SAndreas Gohr if ($this->auth->canDo('modName')) { 6726733c4d7SChris Smith if (empty($name)) { 6736733c4d7SChris Smith msg($this->lang['add_fail'], -1); 67409a5dcd6SMichael Große msg($this->lang['addUser_error_name_missing'], -1); 6756733c4d7SChris Smith return false; 6766733c4d7SChris Smith } 67754cc7aa4SAndreas Gohr } elseif (!empty($name)) { 67809a5dcd6SMichael Große msg($this->lang['add_fail'], -1); 67909a5dcd6SMichael Große msg($this->lang['addUser_error_modName_disabled'], -1); 6806733c4d7SChris Smith return false; 6816733c4d7SChris Smith } 6826733c4d7SChris Smith 6833a97d936SAndreas Gohr if ($this->auth->canDo('modMail')) { 6846733c4d7SChris Smith if (empty($mail)) { 6856733c4d7SChris Smith msg($this->lang['add_fail'], -1); 68609a5dcd6SMichael Große msg($this->lang['addUser_error_mail_missing'], -1); 6876733c4d7SChris Smith return false; 6886733c4d7SChris Smith } 68954cc7aa4SAndreas Gohr } elseif (!empty($mail)) { 69009a5dcd6SMichael Große msg($this->lang['add_fail'], -1); 69109a5dcd6SMichael Große msg($this->lang['addUser_error_modMail_disabled'], -1); 6926733c4d7SChris Smith return false; 6936733c4d7SChris Smith } 6940440ff15Schris 69554cc7aa4SAndreas Gohr if ($ok = $this->auth->triggerUserMod('create', [$user, $pass, $name, $mail, $grps])) { 696a6858c6aSchris msg($this->lang['add_ok'], 1); 697a6858c6aSchris 69800d58927SMichael Hamann if ($INPUT->has('usernotify') && $pass) { 6993a97d936SAndreas Gohr $this->notifyUser($user, $pass); 700a6858c6aSchris } 701a6858c6aSchris } else { 70260b9901bSAndreas Gohr msg($this->lang['add_fail'], -1); 70309a5dcd6SMichael Große msg($this->lang['addUser_error_create_event_failed'], -1); 704a6858c6aSchris } 705a6858c6aSchris 706a6858c6aSchris return $ok; 7070440ff15Schris } 7080440ff15Schris 7090440ff15Schris /** 710c5a7c0c6SGerrit Uitslag * Delete user from auth backend 711c5a7c0c6SGerrit Uitslag * 712c5a7c0c6SGerrit Uitslag * @return bool whether succesful 7130440ff15Schris */ 7143a97d936SAndreas Gohr protected function deleteUser() 7153a97d936SAndreas Gohr { 71600d58927SMichael Hamann global $conf, $INPUT; 7179ec82636SAndreas Gohr 718634d7150SAndreas Gohr if (!checkSecurityToken()) return false; 7193a97d936SAndreas Gohr if (!$this->auth->canDo('delUser')) return false; 7200440ff15Schris 72100d58927SMichael Hamann $selected = $INPUT->arr('delete'); 72200d58927SMichael Hamann if (empty($selected)) return false; 7230440ff15Schris $selected = array_keys($selected); 7240440ff15Schris 725c9a8f912SMichael Klier if (in_array($_SERVER['REMOTE_USER'], $selected)) { 726c8f55459SDamien Regad msg($this->lang['delete_fail_self'], -1); 727c9a8f912SMichael Klier return false; 728c9a8f912SMichael Klier } 729c9a8f912SMichael Klier 73054cc7aa4SAndreas Gohr $count = $this->auth->triggerUserMod('delete', [$selected]); 7310440ff15Schris if ($count == count($selected)) { 7320440ff15Schris $text = str_replace('%d', $count, $this->lang['delete_ok']); 7330440ff15Schris msg("$text.", 1); 7340440ff15Schris } else { 7350440ff15Schris $part1 = str_replace('%d', $count, $this->lang['delete_ok']); 7360440ff15Schris $part2 = str_replace('%d', (count($selected) - $count), $this->lang['delete_fail']); 7370440ff15Schris msg("$part1, $part2", -1); 7380440ff15Schris } 73978c7c8c9Schris 7409ec82636SAndreas Gohr // invalidate all sessions 7419ec82636SAndreas Gohr io_saveFile($conf['cachedir'] . '/sessionpurge', time()); 7429ec82636SAndreas Gohr 74378c7c8c9Schris return true; 74478c7c8c9Schris } 74578c7c8c9Schris 74678c7c8c9Schris /** 74778c7c8c9Schris * Edit user (a user has been selected for editing) 748c5a7c0c6SGerrit Uitslag * 749c5a7c0c6SGerrit Uitslag * @param string $param id of the user 750c5a7c0c6SGerrit Uitslag * @return bool whether succesful 75178c7c8c9Schris */ 7523a97d936SAndreas Gohr protected function editUser($param) 7533a97d936SAndreas Gohr { 754634d7150SAndreas Gohr if (!checkSecurityToken()) return false; 7553a97d936SAndreas Gohr if (!$this->auth->canDo('UserMod')) return false; 7563a97d936SAndreas Gohr $user = $this->auth->cleanUser(preg_replace('/.*[:\/]/', '', $param)); 7573a97d936SAndreas Gohr $userdata = $this->auth->getUserData($user); 75878c7c8c9Schris 75978c7c8c9Schris // no user found? 76078c7c8c9Schris if (!$userdata) { 76178c7c8c9Schris msg($this->lang['edit_usermissing'], -1); 76278c7c8c9Schris return false; 76378c7c8c9Schris } 76478c7c8c9Schris 7653a97d936SAndreas Gohr $this->edit_user = $user; 7663a97d936SAndreas Gohr $this->edit_userdata = $userdata; 76778c7c8c9Schris 76878c7c8c9Schris return true; 7690440ff15Schris } 7700440ff15Schris 7710440ff15Schris /** 772c5a7c0c6SGerrit Uitslag * Modify user in the auth backend (modified user data has been recieved) 773c5a7c0c6SGerrit Uitslag * 774c5a7c0c6SGerrit Uitslag * @return bool whether succesful 7750440ff15Schris */ 7763a97d936SAndreas Gohr protected function modifyUser() 7773a97d936SAndreas Gohr { 77800d58927SMichael Hamann global $conf, $INPUT; 7799ec82636SAndreas Gohr 780634d7150SAndreas Gohr if (!checkSecurityToken()) return false; 7813a97d936SAndreas Gohr if (!$this->auth->canDo('UserMod')) return false; 7820440ff15Schris 78326fb387bSchris // get currently valid user data 7843a97d936SAndreas Gohr $olduser = $this->auth->cleanUser(preg_replace('/.*[:\/]/', '', $INPUT->str('userid_old'))); 7853a97d936SAndreas Gohr $oldinfo = $this->auth->getUserData($olduser); 786073766c6Smatthiasgrimm 78726fb387bSchris // get new user data subject to change 78854cc7aa4SAndreas Gohr [$newuser, $newpass, $newname, $newmail, $newgrps, $passconfirm] = $this->retrieveUser(); 789073766c6Smatthiasgrimm if (empty($newuser)) return false; 7900440ff15Schris 79154cc7aa4SAndreas Gohr $changes = []; 792073766c6Smatthiasgrimm if ($newuser != $olduser) { 7933a97d936SAndreas Gohr if (!$this->auth->canDo('modLogin')) { // sanity check, shouldn't be possible 79426fb387bSchris msg($this->lang['update_fail'], -1); 79526fb387bSchris return false; 79626fb387bSchris } 79726fb387bSchris 79826fb387bSchris // check if $newuser already exists 7993a97d936SAndreas Gohr if ($this->auth->getUserData($newuser)) { 800073766c6Smatthiasgrimm msg(sprintf($this->lang['update_exists'], $newuser), -1); 801a6858c6aSchris $re_edit = true; 8020440ff15Schris } else { 803073766c6Smatthiasgrimm $changes['user'] = $newuser; 8040440ff15Schris } 80593eefc2fSAndreas Gohr } 8063a97d936SAndreas Gohr if ($this->auth->canDo('modPass')) { 8072400ddcbSChristopher Smith if ($newpass || $passconfirm) { 8083a97d936SAndreas Gohr if ($this->verifyPassword($newpass, $passconfirm)) { 809359e9417SChristopher Smith $changes['pass'] = $newpass; 810359e9417SChristopher Smith } else { 811359e9417SChristopher Smith return false; 812359e9417SChristopher Smith } 81354cc7aa4SAndreas Gohr } elseif ($INPUT->has('usernotify')) { 814359e9417SChristopher Smith // no new password supplied, check if we need to generate one (or it stays unchanged) 815359e9417SChristopher Smith $changes['pass'] = auth_pwgen($olduser); 816359e9417SChristopher Smith } 817359e9417SChristopher Smith } 8180440ff15Schris 8193a97d936SAndreas Gohr if (!empty($newname) && $this->auth->canDo('modName') && $newname != $oldinfo['name']) { 820073766c6Smatthiasgrimm $changes['name'] = $newname; 82140d72af6SChristopher Smith } 8223a97d936SAndreas Gohr if (!empty($newmail) && $this->auth->canDo('modMail') && $newmail != $oldinfo['mail']) { 823073766c6Smatthiasgrimm $changes['mail'] = $newmail; 82440d72af6SChristopher Smith } 8253a97d936SAndreas Gohr if (!empty($newgrps) && $this->auth->canDo('modGroups') && $newgrps != $oldinfo['grps']) { 826073766c6Smatthiasgrimm $changes['grps'] = $newgrps; 82740d72af6SChristopher Smith } 8280440ff15Schris 82954cc7aa4SAndreas Gohr if ($ok = $this->auth->triggerUserMod('modify', [$olduser, $changes])) { 8300440ff15Schris msg($this->lang['update_ok'], 1); 831a6858c6aSchris 8326ed3476bSChristopher Smith if ($INPUT->has('usernotify') && !empty($changes['pass'])) { 833a6858c6aSchris $notify = empty($changes['user']) ? $olduser : $newuser; 8343a97d936SAndreas Gohr $this->notifyUser($notify, $changes['pass']); 835a6858c6aSchris } 836a6858c6aSchris 8379ec82636SAndreas Gohr // invalidate all sessions 8389ec82636SAndreas Gohr io_saveFile($conf['cachedir'] . '/sessionpurge', time()); 8390440ff15Schris } else { 8400440ff15Schris msg($this->lang['update_fail'], -1); 8410440ff15Schris } 84278c7c8c9Schris 843a6858c6aSchris if (!empty($re_edit)) { 8443a97d936SAndreas Gohr $this->editUser($olduser); 8450440ff15Schris } 8460440ff15Schris 847a6858c6aSchris return $ok; 848a6858c6aSchris } 849a6858c6aSchris 850a6858c6aSchris /** 851c5a7c0c6SGerrit Uitslag * Send password change notification email 852c5a7c0c6SGerrit Uitslag * 853c5a7c0c6SGerrit Uitslag * @param string $user id of user 854c5a7c0c6SGerrit Uitslag * @param string $password plain text 855c5a7c0c6SGerrit Uitslag * @param bool $status_alert whether status alert should be shown 856c5a7c0c6SGerrit Uitslag * @return bool whether succesful 857a6858c6aSchris */ 8583a97d936SAndreas Gohr protected function notifyUser($user, $password, $status_alert = true) 8593a97d936SAndreas Gohr { 860a6858c6aSchris 861a6858c6aSchris if ($sent = auth_sendPassword($user, $password)) { 862328143f8SChristopher Smith if ($status_alert) { 863a6858c6aSchris msg($this->lang['notify_ok'], 1); 864328143f8SChristopher Smith } 86554cc7aa4SAndreas Gohr } elseif ($status_alert) { 866a6858c6aSchris msg($this->lang['notify_fail'], -1); 867a6858c6aSchris } 868a6858c6aSchris 869a6858c6aSchris return $sent; 870a6858c6aSchris } 871a6858c6aSchris 872a6858c6aSchris /** 873359e9417SChristopher Smith * Verify password meets minimum requirements 874359e9417SChristopher Smith * :TODO: extend to support password strength 875359e9417SChristopher Smith * 876359e9417SChristopher Smith * @param string $password candidate string for new password 877359e9417SChristopher Smith * @param string $confirm repeated password for confirmation 878359e9417SChristopher Smith * @return bool true if meets requirements, false otherwise 879359e9417SChristopher Smith */ 8803a97d936SAndreas Gohr protected function verifyPassword($password, $confirm) 8813a97d936SAndreas Gohr { 882be9008d3SChristopher Smith global $lang; 883359e9417SChristopher Smith 8842400ddcbSChristopher Smith if (empty($password) && empty($confirm)) { 885359e9417SChristopher Smith return false; 886359e9417SChristopher Smith } 887359e9417SChristopher Smith 888359e9417SChristopher Smith if ($password !== $confirm) { 889be9008d3SChristopher Smith msg($lang['regbadpass'], -1); 890359e9417SChristopher Smith return false; 891359e9417SChristopher Smith } 892359e9417SChristopher Smith 893359e9417SChristopher Smith // :TODO: test password for required strength 894359e9417SChristopher Smith 895359e9417SChristopher Smith // if we make it this far the password is good 896359e9417SChristopher Smith return true; 897359e9417SChristopher Smith } 898359e9417SChristopher Smith 899359e9417SChristopher Smith /** 900c5a7c0c6SGerrit Uitslag * Retrieve & clean user data from the form 901a6858c6aSchris * 902c5a7c0c6SGerrit Uitslag * @param bool $clean whether the cleanUser method of the authentication backend is applied 903a6858c6aSchris * @return array (user, password, full name, email, array(groups)) 9040440ff15Schris */ 9053a97d936SAndreas Gohr protected function retrieveUser($clean = true) 9063a97d936SAndreas Gohr { 90751ee2399SGerrit Uitslag /** @var AuthPlugin $auth */ 9087441e340SAndreas Gohr global $auth; 909fbfbbe8aSHakan Sandell global $INPUT; 9100440ff15Schris 91154cc7aa4SAndreas Gohr $user = []; 912fbfbbe8aSHakan Sandell $user[0] = ($clean) ? $auth->cleanUser($INPUT->str('userid')) : $INPUT->str('userid'); 913fbfbbe8aSHakan Sandell $user[1] = $INPUT->str('userpass'); 914fbfbbe8aSHakan Sandell $user[2] = $INPUT->str('username'); 915fbfbbe8aSHakan Sandell $user[3] = $INPUT->str('usermail'); 916fbfbbe8aSHakan Sandell $user[4] = explode(',', $INPUT->str('usergroups')); 917359e9417SChristopher Smith $user[5] = $INPUT->str('userpass2'); // repeated password for confirmation 9180440ff15Schris 919093fe67eSAndreas Gohr $user[4] = array_map(trim(...), $user[4]); 9206547cfc7SGerrit Uitslag if ($clean) { 921093fe67eSAndreas Gohr $user[4] = array_map($auth->cleanGroup(...), $user[4]); 9226547cfc7SGerrit Uitslag } 9237441e340SAndreas Gohr $user[4] = array_filter($user[4]); 9247441e340SAndreas Gohr $user[4] = array_unique($user[4]); 9256547cfc7SGerrit Uitslag if ($user[4] === []) { 9266547cfc7SGerrit Uitslag $user[4] = null; 9276547cfc7SGerrit Uitslag } 9280440ff15Schris 9290440ff15Schris return $user; 9300440ff15Schris } 9310440ff15Schris 932c5a7c0c6SGerrit Uitslag /** 933c5a7c0c6SGerrit Uitslag * Set the filter with the current search terms or clear the filter 934c5a7c0c6SGerrit Uitslag * 935c5a7c0c6SGerrit Uitslag * @param string $op 'new' or 'clear' 936c5a7c0c6SGerrit Uitslag */ 9373a97d936SAndreas Gohr protected function setFilter($op) 9383a97d936SAndreas Gohr { 9390440ff15Schris 94054cc7aa4SAndreas Gohr $this->filter = []; 9410440ff15Schris 9420440ff15Schris if ($op == 'new') { 943a19c9aa0SGerrit Uitslag [$user, /* pass */, $name, $mail, $grps] = $this->retrieveUser(false); 9440440ff15Schris 9453a97d936SAndreas Gohr if (!empty($user)) $this->filter['user'] = $user; 9463a97d936SAndreas Gohr if (!empty($name)) $this->filter['name'] = $name; 9473a97d936SAndreas Gohr if (!empty($mail)) $this->filter['mail'] = $mail; 94854cc7aa4SAndreas Gohr if (!empty($grps)) $this->filter['grps'] = implode('|', $grps); 9490440ff15Schris } 9500440ff15Schris } 9510440ff15Schris 952c5a7c0c6SGerrit Uitslag /** 953c5a7c0c6SGerrit Uitslag * Get the current search terms 954c5a7c0c6SGerrit Uitslag * 955c5a7c0c6SGerrit Uitslag * @return array 956c5a7c0c6SGerrit Uitslag */ 9573a97d936SAndreas Gohr protected function retrieveFilter() 9583a97d936SAndreas Gohr { 959fbfbbe8aSHakan Sandell global $INPUT; 9600440ff15Schris 961fbfbbe8aSHakan Sandell $t_filter = $INPUT->arr('filter'); 9620440ff15Schris 9630440ff15Schris // messy, but this way we ensure we aren't getting any additional crap from malicious users 96454cc7aa4SAndreas Gohr $filter = []; 9650440ff15Schris 9660440ff15Schris if (isset($t_filter['user'])) $filter['user'] = $t_filter['user']; 9670440ff15Schris if (isset($t_filter['name'])) $filter['name'] = $t_filter['name']; 9680440ff15Schris if (isset($t_filter['mail'])) $filter['mail'] = $t_filter['mail']; 9690440ff15Schris if (isset($t_filter['grps'])) $filter['grps'] = $t_filter['grps']; 9700440ff15Schris 9710440ff15Schris return $filter; 9720440ff15Schris } 9730440ff15Schris 974c5a7c0c6SGerrit Uitslag /** 975c5a7c0c6SGerrit Uitslag * Validate and improve the pagination values 976c5a7c0c6SGerrit Uitslag */ 9773a97d936SAndreas Gohr protected function validatePagination() 9783a97d936SAndreas Gohr { 9790440ff15Schris 9803a97d936SAndreas Gohr if ($this->start >= $this->users_total) { 9813a97d936SAndreas Gohr $this->start = $this->users_total - $this->pagesize; 9820440ff15Schris } 9833a97d936SAndreas Gohr if ($this->start < 0) $this->start = 0; 9840440ff15Schris 9853a97d936SAndreas Gohr $this->last = min($this->users_total, $this->start + $this->pagesize); 9860440ff15Schris } 9870440ff15Schris 988c5a7c0c6SGerrit Uitslag /** 989c5a7c0c6SGerrit Uitslag * Return an array of strings to enable/disable pagination buttons 990c5a7c0c6SGerrit Uitslag * 991c5a7c0c6SGerrit Uitslag * @return array with enable/disable attributes 9920440ff15Schris */ 9933a97d936SAndreas Gohr protected function pagination() 9943a97d936SAndreas Gohr { 9950440ff15Schris 99651d94d49Schris $disabled = 'disabled="disabled"'; 99751d94d49Schris 99854cc7aa4SAndreas Gohr $buttons = []; 9993a97d936SAndreas Gohr $buttons['start'] = $buttons['prev'] = ($this->start == 0) ? $disabled : ''; 100051d94d49Schris 10013a97d936SAndreas Gohr if ($this->users_total == -1) { 100251d94d49Schris $buttons['last'] = $disabled; 100351d94d49Schris $buttons['next'] = ''; 100451d94d49Schris } else { 100564159a61SAndreas Gohr $buttons['last'] = $buttons['next'] = 10063a97d936SAndreas Gohr (($this->start + $this->pagesize) >= $this->users_total) ? $disabled : ''; 100751d94d49Schris } 10080440ff15Schris 10093a97d936SAndreas Gohr if ($this->lastdisabled) { 1010462e9e37SMichael Große $buttons['last'] = $disabled; 1011462e9e37SMichael Große } 1012462e9e37SMichael Große 10130440ff15Schris return $buttons; 10140440ff15Schris } 10155c967d3dSChristopher Smith 1016c5a7c0c6SGerrit Uitslag /** 1017c5a7c0c6SGerrit Uitslag * Export a list of users in csv format using the current filter criteria 10185c967d3dSChristopher Smith */ 10193a97d936SAndreas Gohr protected function exportCSV() 10203a97d936SAndreas Gohr { 10215c967d3dSChristopher Smith // list of users for export - based on current filter criteria 10223a97d936SAndreas Gohr $user_list = $this->auth->retrieveUsers(0, 0, $this->filter); 102354cc7aa4SAndreas Gohr $column_headings = [ 10245c967d3dSChristopher Smith $this->lang["user_id"], 10255c967d3dSChristopher Smith $this->lang["user_name"], 10265c967d3dSChristopher Smith $this->lang["user_mail"], 10275c967d3dSChristopher Smith $this->lang["user_groups"] 102854cc7aa4SAndreas Gohr ]; 10295c967d3dSChristopher Smith 10305c967d3dSChristopher Smith // ============================================================================================== 10315c967d3dSChristopher Smith // GENERATE OUTPUT 10325c967d3dSChristopher Smith // normal headers for downloading... 10335c967d3dSChristopher Smith header('Content-type: text/csv;charset=utf-8'); 10345c967d3dSChristopher Smith header('Content-Disposition: attachment; filename="wikiusers.csv"'); 10355c967d3dSChristopher Smith# // for debugging assistance, send as text plain to the browser 10365c967d3dSChristopher Smith# header('Content-type: text/plain;charset=utf-8'); 10375c967d3dSChristopher Smith 10385c967d3dSChristopher Smith // output the csv 10395c967d3dSChristopher Smith $fd = fopen('php://output', 'w'); 1040abc2dfe1SAndreas Gohr fputcsv($fd, $column_headings, ',', '"', "\\"); 10415c967d3dSChristopher Smith foreach ($user_list as $user => $info) { 104254cc7aa4SAndreas Gohr $line = [$user, $info['name'], $info['mail'], implode(',', $info['grps'])]; 1043abc2dfe1SAndreas Gohr fputcsv($fd, $line, ',', '"', "\\"); 10445c967d3dSChristopher Smith } 10455c967d3dSChristopher Smith fclose($fd); 10463a97d936SAndreas Gohr if (defined('DOKU_UNITTEST')) { 10473a97d936SAndreas Gohr return; 10483a97d936SAndreas Gohr } 1049b2c01466SChristopher Smith 10505c967d3dSChristopher Smith die; 10515c967d3dSChristopher Smith } 1052ae1afd2fSChristopher Smith 1053c5a7c0c6SGerrit Uitslag /** 1054c5a7c0c6SGerrit Uitslag * Import a file of users in csv format 1055ae1afd2fSChristopher Smith * 1056ae1afd2fSChristopher Smith * csv file should have 4 columns, user_id, full name, email, groups (comma separated) 1057c5a7c0c6SGerrit Uitslag * 10585ba64050SChristopher Smith * @return bool whether successful 1059ae1afd2fSChristopher Smith */ 10603a97d936SAndreas Gohr protected function importCSV() 10613a97d936SAndreas Gohr { 1062ae1afd2fSChristopher Smith // check we are allowed to add users 1063ae1afd2fSChristopher Smith if (!checkSecurityToken()) return false; 10643a97d936SAndreas Gohr if (!$this->auth->canDo('addUser')) return false; 1065ae1afd2fSChristopher Smith 1066ae1afd2fSChristopher Smith // check file uploaded ok. 10677d34963bSAndreas Gohr if ( 10687d34963bSAndreas Gohr empty($_FILES['import']['size']) || 10693a97d936SAndreas Gohr !empty($_FILES['import']['error']) && $this->isUploadedFile($_FILES['import']['tmp_name']) 107064159a61SAndreas Gohr ) { 1071ae1afd2fSChristopher Smith msg($this->lang['import_error_upload'], -1); 1072ae1afd2fSChristopher Smith return false; 1073ae1afd2fSChristopher Smith } 1074ae1afd2fSChristopher Smith // retrieve users from the file 107554cc7aa4SAndreas Gohr $this->import_failures = []; 1076ae1afd2fSChristopher Smith $import_success_count = 0; 1077ae1afd2fSChristopher Smith $import_fail_count = 0; 1078ae1afd2fSChristopher Smith $line = 0; 1079ae1afd2fSChristopher Smith $fd = fopen($_FILES['import']['tmp_name'], 'r'); 1080ae1afd2fSChristopher Smith if ($fd) { 1081ae1afd2fSChristopher Smith while ($csv = fgets($fd)) { 108254cc7aa4SAndreas Gohr if (!Clean::isUtf8($csv)) { 108353c68e5cSAndreas Gohr $csv = Conversion::fromLatin1($csv); 1084efcec72bSChristopher Smith } 1085abc2dfe1SAndreas Gohr $raw = str_getcsv($csv, ',', '"', "\\"); 1086ae1afd2fSChristopher Smith $error = ''; // clean out any errors from the previous line 1087ae1afd2fSChristopher Smith // data checks... 1088ae1afd2fSChristopher Smith if (1 == ++$line) { 1089ae1afd2fSChristopher Smith if ($raw[0] == 'user_id' || $raw[0] == $this->lang['user_id']) continue; // skip headers 1090ae1afd2fSChristopher Smith } 1091ae1afd2fSChristopher Smith if (count($raw) < 4) { // need at least four fields 1092ae1afd2fSChristopher Smith $import_fail_count++; 1093ae1afd2fSChristopher Smith $error = sprintf($this->lang['import_error_fields'], count($raw)); 109454cc7aa4SAndreas Gohr $this->import_failures[$line] = ['error' => $error, 'user' => $raw, 'orig' => $csv]; 1095ae1afd2fSChristopher Smith continue; 1096ae1afd2fSChristopher Smith } 1097ae1afd2fSChristopher Smith array_splice($raw, 1, 0, auth_pwgen()); // splice in a generated password 10983a97d936SAndreas Gohr $clean = $this->cleanImportUser($raw, $error); 10993a97d936SAndreas Gohr if ($clean && $this->importUser($clean, $error)) { 11003a97d936SAndreas Gohr $sent = $this->notifyUser($clean[0], $clean[1], false); 1101328143f8SChristopher Smith if (!$sent) { 1102328143f8SChristopher Smith msg(sprintf($this->lang['import_notify_fail'], $clean[0], $clean[3]), -1); 1103328143f8SChristopher Smith } 1104ae1afd2fSChristopher Smith $import_success_count++; 1105ae1afd2fSChristopher Smith } else { 1106ae1afd2fSChristopher Smith $import_fail_count++; 1107e73725baSChristopher Smith array_splice($raw, 1, 1); // remove the spliced in password 110854cc7aa4SAndreas Gohr $this->import_failures[$line] = ['error' => $error, 'user' => $raw, 'orig' => $csv]; 1109ae1afd2fSChristopher Smith } 1110ae1afd2fSChristopher Smith } 111164159a61SAndreas Gohr msg( 111264159a61SAndreas Gohr sprintf( 111364159a61SAndreas Gohr $this->lang['import_success_count'], 111464159a61SAndreas Gohr ($import_success_count + $import_fail_count), 111564159a61SAndreas Gohr $import_success_count 111664159a61SAndreas Gohr ), 111764159a61SAndreas Gohr ($import_success_count ? 1 : -1) 111864159a61SAndreas Gohr ); 1119ae1afd2fSChristopher Smith if ($import_fail_count) { 1120ae1afd2fSChristopher Smith msg(sprintf($this->lang['import_failure_count'], $import_fail_count), -1); 1121ae1afd2fSChristopher Smith } 1122ae1afd2fSChristopher Smith } else { 1123ae1afd2fSChristopher Smith msg($this->lang['import_error_readfail'], -1); 1124ae1afd2fSChristopher Smith } 1125ae1afd2fSChristopher Smith 1126ae1afd2fSChristopher Smith // save import failures into the session 1127ae1afd2fSChristopher Smith if (!headers_sent()) { 1128ae1afd2fSChristopher Smith session_start(); 11293a97d936SAndreas Gohr $_SESSION['import_failures'] = $this->import_failures; 1130ae1afd2fSChristopher Smith session_write_close(); 1131ae1afd2fSChristopher Smith } 1132c5a7c0c6SGerrit Uitslag return true; 1133ae1afd2fSChristopher Smith } 1134ae1afd2fSChristopher Smith 1135c5a7c0c6SGerrit Uitslag /** 1136786dfb0eSGerrit Uitslag * Returns cleaned user data 1137c5a7c0c6SGerrit Uitslag * 1138c5a7c0c6SGerrit Uitslag * @param array $candidate raw values of line from input file 1139253d4b48SGerrit Uitslag * @param string $error 1140253d4b48SGerrit Uitslag * @return array|false cleaned data or false 1141c5a7c0c6SGerrit Uitslag */ 11423a97d936SAndreas Gohr protected function cleanImportUser($candidate, &$error) 11433a97d936SAndreas Gohr { 1144ae1afd2fSChristopher Smith global $INPUT; 1145ae1afd2fSChristopher Smith 11463a97d936SAndreas Gohr // FIXME kludgy .... 1147ae1afd2fSChristopher Smith $INPUT->set('userid', $candidate[0]); 1148ae1afd2fSChristopher Smith $INPUT->set('userpass', $candidate[1]); 1149ae1afd2fSChristopher Smith $INPUT->set('username', $candidate[2]); 1150ae1afd2fSChristopher Smith $INPUT->set('usermail', $candidate[3]); 1151ae1afd2fSChristopher Smith $INPUT->set('usergroups', $candidate[4]); 1152ae1afd2fSChristopher Smith 11533a97d936SAndreas Gohr $cleaned = $this->retrieveUser(); 115454cc7aa4SAndreas Gohr [$user, /* pass */, $name, $mail, /* grps */] = $cleaned; 1155ae1afd2fSChristopher Smith if (empty($user)) { 1156ae1afd2fSChristopher Smith $error = $this->lang['import_error_baduserid']; 1157ae1afd2fSChristopher Smith return false; 1158ae1afd2fSChristopher Smith } 1159ae1afd2fSChristopher Smith 1160ae1afd2fSChristopher Smith // no need to check password, handled elsewhere 1161ae1afd2fSChristopher Smith 11623a97d936SAndreas Gohr if (!($this->auth->canDo('modName') xor empty($name))) { 1163ae1afd2fSChristopher Smith $error = $this->lang['import_error_badname']; 1164ae1afd2fSChristopher Smith return false; 1165ae1afd2fSChristopher Smith } 1166ae1afd2fSChristopher Smith 11673a97d936SAndreas Gohr if ($this->auth->canDo('modMail')) { 1168*73dc0a89SAndreas Gohr if (empty($mail) || !MailUtils::isValid($mail)) { 1169ae1afd2fSChristopher Smith $error = $this->lang['import_error_badmail']; 1170ae1afd2fSChristopher Smith return false; 1171ae1afd2fSChristopher Smith } 117254cc7aa4SAndreas Gohr } elseif (!empty($mail)) { 1173328143f8SChristopher Smith $error = $this->lang['import_error_badmail']; 1174328143f8SChristopher Smith return false; 1175328143f8SChristopher Smith } 1176ae1afd2fSChristopher Smith 1177ae1afd2fSChristopher Smith return $cleaned; 1178ae1afd2fSChristopher Smith } 1179ae1afd2fSChristopher Smith 1180c5a7c0c6SGerrit Uitslag /** 1181c5a7c0c6SGerrit Uitslag * Adds imported user to auth backend 1182c5a7c0c6SGerrit Uitslag * 1183c5a7c0c6SGerrit Uitslag * Required a check of canDo('addUser') before 1184c5a7c0c6SGerrit Uitslag * 1185c5a7c0c6SGerrit Uitslag * @param array $user data of user 1186c5a7c0c6SGerrit Uitslag * @param string &$error reference catched error message 11875ba64050SChristopher Smith * @return bool whether successful 1188c5a7c0c6SGerrit Uitslag */ 11893a97d936SAndreas Gohr protected function importUser($user, &$error) 11903a97d936SAndreas Gohr { 11913a97d936SAndreas Gohr if (!$this->auth->triggerUserMod('create', $user)) { 1192ae1afd2fSChristopher Smith $error = $this->lang['import_error_create']; 1193ae1afd2fSChristopher Smith return false; 1194ae1afd2fSChristopher Smith } 1195ae1afd2fSChristopher Smith 1196ae1afd2fSChristopher Smith return true; 1197ae1afd2fSChristopher Smith } 1198ae1afd2fSChristopher Smith 1199c5a7c0c6SGerrit Uitslag /** 1200c5a7c0c6SGerrit Uitslag * Downloads failures as csv file 1201c5a7c0c6SGerrit Uitslag */ 12023a97d936SAndreas Gohr protected function downloadImportFailures() 12033a97d936SAndreas Gohr { 1204ae1afd2fSChristopher Smith 1205ae1afd2fSChristopher Smith // ============================================================================================== 1206ae1afd2fSChristopher Smith // GENERATE OUTPUT 1207ae1afd2fSChristopher Smith // normal headers for downloading... 1208ae1afd2fSChristopher Smith header('Content-type: text/csv;charset=utf-8'); 1209ae1afd2fSChristopher Smith header('Content-Disposition: attachment; filename="importfails.csv"'); 1210ae1afd2fSChristopher Smith# // for debugging assistance, send as text plain to the browser 1211ae1afd2fSChristopher Smith# header('Content-type: text/plain;charset=utf-8'); 1212ae1afd2fSChristopher Smith 1213ae1afd2fSChristopher Smith // output the csv 1214ae1afd2fSChristopher Smith $fd = fopen('php://output', 'w'); 12153a97d936SAndreas Gohr foreach ($this->import_failures as $fail) { 121654cc7aa4SAndreas Gohr fwrite($fd, $fail['orig']); 1217ae1afd2fSChristopher Smith } 1218ae1afd2fSChristopher Smith fclose($fd); 1219ae1afd2fSChristopher Smith die; 1220ae1afd2fSChristopher Smith } 1221ae1afd2fSChristopher Smith 1222b2c01466SChristopher Smith /** 1223b2c01466SChristopher Smith * wrapper for is_uploaded_file to facilitate overriding by test suite 1224253d4b48SGerrit Uitslag * 1225253d4b48SGerrit Uitslag * @param string $file filename 1226253d4b48SGerrit Uitslag * @return bool 1227b2c01466SChristopher Smith */ 12283a97d936SAndreas Gohr protected function isUploadedFile($file) 12293a97d936SAndreas Gohr { 1230b2c01466SChristopher Smith return is_uploaded_file($file); 1231b2c01466SChristopher Smith } 12320440ff15Schris} 1233