10440ff15Schris<?php 20440ff15Schris/* 30440ff15Schris * User Manager 40440ff15Schris * 50440ff15Schris * Dokuwiki Admin Plugin 60440ff15Schris * 70440ff15Schris * This version of the user manager has been modified to only work with 80440ff15Schris * objectified version of auth system 90440ff15Schris * 100440ff15Schris * @author neolao <neolao@neolao.com> 110440ff15Schris * @author Chris Smith <chris@jalakai.co.uk> 120440ff15Schris */ 130440ff15Schris 140440ff15Schris/** 150440ff15Schris * All DokuWiki plugins to extend the admin function 160440ff15Schris * need to inherit from this class 170440ff15Schris */ 18*3a97d936SAndreas Gohrclass admin_plugin_usermanager extends DokuWiki_Admin_Plugin 19*3a97d936SAndreas Gohr{ 20*3a97d936SAndreas Gohr const IMAGE_DIR = DOKU_BASE.'lib/plugins/usermanager/images/'; 210440ff15Schris 22*3a97d936SAndreas Gohr protected $auth = null; // auth object 23*3a97d936SAndreas Gohr protected $users_total = 0; // number of registered users 24*3a97d936SAndreas Gohr protected $filter = array(); // user selection filter(s) 25*3a97d936SAndreas Gohr protected $start = 0; // index of first user to be displayed 26*3a97d936SAndreas Gohr protected $last = 0; // index of the last user to be displayed 27*3a97d936SAndreas Gohr protected $pagesize = 20; // number of users to list on one page 28*3a97d936SAndreas Gohr protected $edit_user = ''; // set to user selected for editing 29*3a97d936SAndreas Gohr protected $edit_userdata = array(); 30*3a97d936SAndreas Gohr protected $disabled = ''; // if disabled set to explanatory string 31*3a97d936SAndreas Gohr protected $import_failures = array(); 32*3a97d936SAndreas Gohr protected $lastdisabled = false; // set to true if last user is unknown and last button is hence buggy 330440ff15Schris 340440ff15Schris /** 350440ff15Schris * Constructor 360440ff15Schris */ 37*3a97d936SAndreas Gohr public function __construct() 38*3a97d936SAndreas Gohr { 39c5a7c0c6SGerrit Uitslag /** @var DokuWiki_Auth_Plugin $auth */ 400440ff15Schris global $auth; 410440ff15Schris 420440ff15Schris $this->setupLocale(); 4351d94d49Schris 4451d94d49Schris if (!isset($auth)) { 45*3a97d936SAndreas Gohr $this->disabled = $this->lang['noauth']; 4682fd59b6SAndreas Gohr } elseif (!$auth->canDo('getUsers')) { 47*3a97d936SAndreas Gohr $this->disabled = $this->lang['nosupport']; 4851d94d49Schris } else { 4951d94d49Schris // we're good to go 50*3a97d936SAndreas Gohr $this->auth = & $auth; 5151d94d49Schris } 52ae1afd2fSChristopher Smith 53ae1afd2fSChristopher Smith // attempt to retrieve any import failures from the session 540e80bb5eSChristopher Smith if (!empty($_SESSION['import_failures'])) { 55*3a97d936SAndreas Gohr $this->import_failures = $_SESSION['import_failures']; 56ae1afd2fSChristopher Smith } 570440ff15Schris } 580440ff15Schris 590440ff15Schris /** 60c5a7c0c6SGerrit Uitslag * Return prompt for admin menu 61253d4b48SGerrit Uitslag * 62253d4b48SGerrit Uitslag * @param string $language 63253d4b48SGerrit Uitslag * @return string 640440ff15Schris */ 65*3a97d936SAndreas Gohr public function getMenuText($language) 66*3a97d936SAndreas Gohr { 670440ff15Schris 68*3a97d936SAndreas Gohr if (!is_null($this->auth)) 690440ff15Schris return parent::getMenuText($language); 700440ff15Schris 71*3a97d936SAndreas Gohr return $this->getLang('menu').' '.$this->disabled; 720440ff15Schris } 730440ff15Schris 740440ff15Schris /** 750440ff15Schris * return sort order for position in admin menu 76253d4b48SGerrit Uitslag * 77253d4b48SGerrit Uitslag * @return int 780440ff15Schris */ 79*3a97d936SAndreas Gohr public function getMenuSort() 80*3a97d936SAndreas Gohr { 810440ff15Schris return 2; 820440ff15Schris } 830440ff15Schris 840440ff15Schris /** 8567a31a83SMichael Große * @return int current start value for pageination 8667a31a83SMichael Große */ 87*3a97d936SAndreas Gohr public function getStart() 88*3a97d936SAndreas Gohr { 89*3a97d936SAndreas Gohr return $this->start; 9067a31a83SMichael Große } 9167a31a83SMichael Große 9267a31a83SMichael Große /** 9367a31a83SMichael Große * @return int number of users per page 9467a31a83SMichael Große */ 95*3a97d936SAndreas Gohr public function getPagesize() 96*3a97d936SAndreas Gohr { 97*3a97d936SAndreas Gohr return $this->pagesize; 9867a31a83SMichael Große } 9967a31a83SMichael Große 10067a31a83SMichael Große /** 101462e9e37SMichael Große * @param boolean $lastdisabled 102462e9e37SMichael Große */ 103*3a97d936SAndreas Gohr public function setLastdisabled($lastdisabled) 104*3a97d936SAndreas Gohr { 105*3a97d936SAndreas Gohr $this->lastdisabled = $lastdisabled; 106462e9e37SMichael Große } 107462e9e37SMichael Große 108462e9e37SMichael Große /** 109c5a7c0c6SGerrit Uitslag * Handle user request 110253d4b48SGerrit Uitslag * 111253d4b48SGerrit Uitslag * @return bool 1120440ff15Schris */ 113*3a97d936SAndreas Gohr public function handle() 114*3a97d936SAndreas Gohr { 11500d58927SMichael Hamann global $INPUT; 116*3a97d936SAndreas Gohr if (is_null($this->auth)) return false; 1170440ff15Schris 1180440ff15Schris // extract the command and any specific parameters 1190440ff15Schris // submit button name is of the form - fn[cmd][param(s)] 12000d58927SMichael Hamann $fn = $INPUT->param('fn'); 1210440ff15Schris 1220440ff15Schris if (is_array($fn)) { 1230440ff15Schris $cmd = key($fn); 1240440ff15Schris $param = is_array($fn[$cmd]) ? key($fn[$cmd]) : null; 1250440ff15Schris } else { 1260440ff15Schris $cmd = $fn; 1270440ff15Schris $param = null; 1280440ff15Schris } 1290440ff15Schris 1300440ff15Schris if ($cmd != "search") { 131*3a97d936SAndreas Gohr $this->start = $INPUT->int('start', 0); 132*3a97d936SAndreas Gohr $this->filter = $this->retrieveFilter(); 1330440ff15Schris } 1340440ff15Schris 1350440ff15Schris switch ($cmd) { 136*3a97d936SAndreas Gohr case "add": 137*3a97d936SAndreas Gohr $this->addUser(); 1380440ff15Schris break; 139*3a97d936SAndreas Gohr case "delete": 140*3a97d936SAndreas Gohr $this->deleteUser(); 141*3a97d936SAndreas Gohr break; 142*3a97d936SAndreas Gohr case "modify": 143*3a97d936SAndreas Gohr $this->modifyUser(); 144*3a97d936SAndreas Gohr break; 145*3a97d936SAndreas Gohr case "edit": 146*3a97d936SAndreas Gohr $this->editUser($param); 147*3a97d936SAndreas Gohr break; 148*3a97d936SAndreas Gohr case "search": 149*3a97d936SAndreas Gohr $this->setFilter($param); 150*3a97d936SAndreas Gohr $this->start = 0; 151*3a97d936SAndreas Gohr break; 152*3a97d936SAndreas Gohr case "export": 153*3a97d936SAndreas Gohr $this->exportCSV(); 154*3a97d936SAndreas Gohr break; 155*3a97d936SAndreas Gohr case "import": 156*3a97d936SAndreas Gohr $this->importCSV(); 157*3a97d936SAndreas Gohr break; 158*3a97d936SAndreas Gohr case "importfails": 159*3a97d936SAndreas Gohr $this->downloadImportFailures(); 160*3a97d936SAndreas Gohr break; 1610440ff15Schris } 1620440ff15Schris 163*3a97d936SAndreas Gohr $this->users_total = $this->auth->canDo('getUserCount') ? $this->auth->getUserCount($this->filter) : -1; 1640440ff15Schris 1650440ff15Schris // page handling 1660440ff15Schris switch ($cmd) { 167*3a97d936SAndreas Gohr case 'start': 168*3a97d936SAndreas Gohr $this->start = 0; 169*3a97d936SAndreas Gohr break; 170*3a97d936SAndreas Gohr case 'prev': 171*3a97d936SAndreas Gohr $this->start -= $this->pagesize; 172*3a97d936SAndreas Gohr break; 173*3a97d936SAndreas Gohr case 'next': 174*3a97d936SAndreas Gohr $this->start += $this->pagesize; 175*3a97d936SAndreas Gohr break; 176*3a97d936SAndreas Gohr case 'last': 177*3a97d936SAndreas Gohr $this->start = $this->users_total; 178*3a97d936SAndreas Gohr break; 1790440ff15Schris } 180*3a97d936SAndreas Gohr $this->validatePagination(); 181c5a7c0c6SGerrit Uitslag return true; 1820440ff15Schris } 1830440ff15Schris 1840440ff15Schris /** 185c5a7c0c6SGerrit Uitslag * Output appropriate html 186253d4b48SGerrit Uitslag * 187253d4b48SGerrit Uitslag * @return bool 1880440ff15Schris */ 189*3a97d936SAndreas Gohr public function html() 190*3a97d936SAndreas Gohr { 1910440ff15Schris global $ID; 1920440ff15Schris 193*3a97d936SAndreas Gohr if (is_null($this->auth)) { 1940440ff15Schris print $this->lang['badauth']; 1950440ff15Schris return false; 1960440ff15Schris } 1970440ff15Schris 198*3a97d936SAndreas Gohr $user_list = $this->auth->retrieveUsers($this->start, $this->pagesize, $this->filter); 1990440ff15Schris 200*3a97d936SAndreas Gohr $page_buttons = $this->pagination(); 201*3a97d936SAndreas Gohr $delete_disable = $this->auth->canDo('delUser') ? '' : 'disabled="disabled"'; 2020440ff15Schris 203*3a97d936SAndreas Gohr $editable = $this->auth->canDo('UserMod'); 204*3a97d936SAndreas Gohr $export_label = empty($this->filter) ? $this->lang['export_all'] : $this->lang['export_filtered']; 2056154103cSmatthiasgrimm 2060440ff15Schris print $this->locale_xhtml('intro'); 2070440ff15Schris print $this->locale_xhtml('list'); 2080440ff15Schris 20958dde80dSAnika Henke ptln("<div id=\"user__manager\">"); 21058dde80dSAnika Henke ptln("<div class=\"level2\">"); 2110440ff15Schris 212*3a97d936SAndreas Gohr if ($this->users_total > 0) { 21364159a61SAndreas Gohr ptln( 21464159a61SAndreas Gohr "<p>" . sprintf( 21564159a61SAndreas Gohr $this->lang['summary'], 216*3a97d936SAndreas Gohr $this->start + 1, 217*3a97d936SAndreas Gohr $this->last, 218*3a97d936SAndreas Gohr $this->users_total, 219*3a97d936SAndreas Gohr $this->auth->getUserCount() 22064159a61SAndreas Gohr ) . "</p>" 22164159a61SAndreas Gohr ); 2220440ff15Schris } else { 223*3a97d936SAndreas Gohr if ($this->users_total < 0) { 224a102b175SGerrit Uitslag $allUserTotal = 0; 225a102b175SGerrit Uitslag } else { 226*3a97d936SAndreas Gohr $allUserTotal = $this->auth->getUserCount(); 227a102b175SGerrit Uitslag } 228a102b175SGerrit Uitslag ptln("<p>".sprintf($this->lang['nonefound'], $allUserTotal)."</p>"); 2290440ff15Schris } 2300440ff15Schris ptln("<form action=\"".wl($ID)."\" method=\"post\">"); 231634d7150SAndreas Gohr formSecurityToken(); 232c7b28ffdSAnika Henke ptln(" <div class=\"table\">"); 2330440ff15Schris ptln(" <table class=\"inline\">"); 2340440ff15Schris ptln(" <thead>"); 2350440ff15Schris ptln(" <tr>"); 23664159a61SAndreas Gohr ptln(" <th> </th> 23764159a61SAndreas Gohr <th>".$this->lang["user_id"]."</th> 23864159a61SAndreas Gohr <th>".$this->lang["user_name"]."</th> 23964159a61SAndreas Gohr <th>".$this->lang["user_mail"]."</th> 24064159a61SAndreas Gohr <th>".$this->lang["user_groups"]."</th>"); 2410440ff15Schris ptln(" </tr>"); 2420440ff15Schris 2430440ff15Schris ptln(" <tr>"); 24464159a61SAndreas Gohr ptln(" <td class=\"rightalign\"><input type=\"image\" src=\"". 245*3a97d936SAndreas Gohr self::IMAGE_DIR."search.png\" name=\"fn[search][new]\" title=\"". 24664159a61SAndreas Gohr $this->lang['search_prompt']."\" alt=\"".$this->lang['search']."\" class=\"button\" /></td>"); 24764159a61SAndreas Gohr ptln(" <td><input type=\"text\" name=\"userid\" class=\"edit\" value=\"". 248*3a97d936SAndreas Gohr $this->htmlFilter('user')."\" /></td>"); 24964159a61SAndreas Gohr ptln(" <td><input type=\"text\" name=\"username\" class=\"edit\" value=\"". 250*3a97d936SAndreas Gohr $this->htmlFilter('name')."\" /></td>"); 25164159a61SAndreas Gohr ptln(" <td><input type=\"text\" name=\"usermail\" class=\"edit\" value=\"". 252*3a97d936SAndreas Gohr $this->htmlFilter('mail')."\" /></td>"); 25364159a61SAndreas Gohr ptln(" <td><input type=\"text\" name=\"usergroups\" class=\"edit\" value=\"". 254*3a97d936SAndreas Gohr $this->htmlFilter('grps')."\" /></td>"); 2550440ff15Schris ptln(" </tr>"); 2560440ff15Schris ptln(" </thead>"); 2570440ff15Schris 258*3a97d936SAndreas Gohr if ($this->users_total) { 2590440ff15Schris ptln(" <tbody>"); 2600440ff15Schris foreach ($user_list as $user => $userinfo) { 2610440ff15Schris extract($userinfo); 262c5a7c0c6SGerrit Uitslag /** 263c5a7c0c6SGerrit Uitslag * @var string $name 264c5a7c0c6SGerrit Uitslag * @var string $pass 265c5a7c0c6SGerrit Uitslag * @var string $mail 266c5a7c0c6SGerrit Uitslag * @var array $grps 267c5a7c0c6SGerrit Uitslag */ 2680440ff15Schris $groups = join(', ', $grps); 269a2c0246eSAnika Henke ptln(" <tr class=\"user_info\">"); 27064159a61SAndreas Gohr ptln(" <td class=\"centeralign\"><input type=\"checkbox\" name=\"delete[".hsc($user). 27164159a61SAndreas Gohr "]\" ".$delete_disable." /></td>"); 2722365d73dSAnika Henke if ($editable) { 273f23f9594SAndreas Gohr ptln(" <td><a href=\"".wl($ID, array('fn[edit]['.$user.']' => 1, 27477d19185SAndreas Gohr 'do' => 'admin', 27577d19185SAndreas Gohr 'page' => 'usermanager', 27677d19185SAndreas Gohr 'sectok' => getSecurityToken())). 27777d19185SAndreas Gohr "\" title=\"".$this->lang['edit_prompt']."\">".hsc($user)."</a></td>"); 2782365d73dSAnika Henke } else { 2792365d73dSAnika Henke ptln(" <td>".hsc($user)."</td>"); 2802365d73dSAnika Henke } 2812365d73dSAnika Henke ptln(" <td>".hsc($name)."</td><td>".hsc($mail)."</td><td>".hsc($groups)."</td>"); 2820440ff15Schris ptln(" </tr>"); 2830440ff15Schris } 2840440ff15Schris ptln(" </tbody>"); 2850440ff15Schris } 2860440ff15Schris 2870440ff15Schris ptln(" <tbody>"); 2882365d73dSAnika Henke ptln(" <tr><td colspan=\"5\" class=\"centeralign\">"); 289a2c0246eSAnika Henke ptln(" <span class=\"medialeft\">"); 29064159a61SAndreas Gohr ptln(" <button type=\"submit\" name=\"fn[delete]\" id=\"usrmgr__del\" ".$delete_disable.">". 29164159a61SAndreas Gohr $this->lang['delete_selected']."</button>"); 29276c49356SMike Wilmes ptln(" </span>"); 29376c49356SMike Wilmes ptln(" <span class=\"mediaright\">"); 29464159a61SAndreas Gohr ptln(" <button type=\"submit\" name=\"fn[start]\" ".$page_buttons['start'].">". 29564159a61SAndreas Gohr $this->lang['start']."</button>"); 29664159a61SAndreas Gohr ptln(" <button type=\"submit\" name=\"fn[prev]\" ".$page_buttons['prev'].">". 29764159a61SAndreas Gohr $this->lang['prev']."</button>"); 29864159a61SAndreas Gohr ptln(" <button type=\"submit\" name=\"fn[next]\" ".$page_buttons['next'].">". 29964159a61SAndreas Gohr $this->lang['next']."</button>"); 30064159a61SAndreas Gohr ptln(" <button type=\"submit\" name=\"fn[last]\" ".$page_buttons['last'].">". 30164159a61SAndreas Gohr $this->lang['last']."</button>"); 30276c49356SMike Wilmes ptln(" </span>"); 303*3a97d936SAndreas Gohr if (!empty($this->filter)) { 304ae614416SAnika Henke ptln(" <button type=\"submit\" name=\"fn[search][clear]\">".$this->lang['clear']."</button>"); 3055c967d3dSChristopher Smith } 306ae614416SAnika Henke ptln(" <button type=\"submit\" name=\"fn[export]\">".$export_label."</button>"); 3075164d9c9SAnika Henke ptln(" <input type=\"hidden\" name=\"do\" value=\"admin\" />"); 3085164d9c9SAnika Henke ptln(" <input type=\"hidden\" name=\"page\" value=\"usermanager\" />"); 309daf4ca4eSAnika Henke 310*3a97d936SAndreas Gohr $this->htmlFilterSettings(2); 311daf4ca4eSAnika Henke 3120440ff15Schris ptln(" </td></tr>"); 3130440ff15Schris ptln(" </tbody>"); 3140440ff15Schris ptln(" </table>"); 315c7b28ffdSAnika Henke ptln(" </div>"); 3160440ff15Schris 3170440ff15Schris ptln("</form>"); 3180440ff15Schris ptln("</div>"); 3190440ff15Schris 320*3a97d936SAndreas Gohr $style = $this->edit_user ? " class=\"edit_user\"" : ""; 3210440ff15Schris 322*3a97d936SAndreas Gohr if ($this->auth->canDo('addUser')) { 3230440ff15Schris ptln("<div".$style.">"); 3240440ff15Schris print $this->locale_xhtml('add'); 3250440ff15Schris ptln(" <div class=\"level2\">"); 3260440ff15Schris 327*3a97d936SAndreas Gohr $this->htmlUserForm('add', null, array(), 4); 3280440ff15Schris 3290440ff15Schris ptln(" </div>"); 3300440ff15Schris ptln("</div>"); 3310440ff15Schris } 3320440ff15Schris 333*3a97d936SAndreas Gohr if ($this->edit_user && $this->auth->canDo('UserMod')) { 334c632fc69SAndreas Gohr ptln("<div".$style." id=\"scroll__here\">"); 3350440ff15Schris print $this->locale_xhtml('edit'); 3360440ff15Schris ptln(" <div class=\"level2\">"); 3370440ff15Schris 338*3a97d936SAndreas Gohr $this->htmlUserForm('modify', $this->edit_user, $this->edit_userdata, 4); 3390440ff15Schris 3400440ff15Schris ptln(" </div>"); 3410440ff15Schris ptln("</div>"); 3420440ff15Schris } 343ae1afd2fSChristopher Smith 344*3a97d936SAndreas Gohr if ($this->auth->canDo('addUser')) { 345*3a97d936SAndreas Gohr $this->htmlImportForm(); 346ae1afd2fSChristopher Smith } 34758dde80dSAnika Henke ptln("</div>"); 348c5a7c0c6SGerrit Uitslag return true; 3490440ff15Schris } 3500440ff15Schris 35182fd59b6SAndreas Gohr /** 352c5a7c0c6SGerrit Uitslag * Display form to add or modify a user 353c5a7c0c6SGerrit Uitslag * 354c5a7c0c6SGerrit Uitslag * @param string $cmd 'add' or 'modify' 355c5a7c0c6SGerrit Uitslag * @param string $user id of user 356c5a7c0c6SGerrit Uitslag * @param array $userdata array with name, mail, pass and grps 357c5a7c0c6SGerrit Uitslag * @param int $indent 35882fd59b6SAndreas Gohr */ 359*3a97d936SAndreas Gohr protected function htmlUserForm($cmd, $user = '', $userdata = array(), $indent = 0) 360*3a97d936SAndreas Gohr { 361a6858c6aSchris global $conf; 362bb4866bdSchris global $ID; 363be9008d3SChristopher Smith global $lang; 36478c7c8c9Schris 36578c7c8c9Schris $name = $mail = $groups = ''; 366a6858c6aSchris $notes = array(); 3670440ff15Schris 3680440ff15Schris if ($user) { 36978c7c8c9Schris extract($userdata); 37078c7c8c9Schris if (!empty($grps)) $groups = join(',', $grps); 371a6858c6aSchris } else { 372a6858c6aSchris $notes[] = sprintf($this->lang['note_group'], $conf['defaultgroup']); 3730440ff15Schris } 3740440ff15Schris 3750440ff15Schris ptln("<form action=\"".wl($ID)."\" method=\"post\">", $indent); 376634d7150SAndreas Gohr formSecurityToken(); 377c7b28ffdSAnika Henke ptln(" <div class=\"table\">", $indent); 3780440ff15Schris ptln(" <table class=\"inline\">", $indent); 3790440ff15Schris ptln(" <thead>", $indent); 3800440ff15Schris ptln(" <tr><th>".$this->lang["field"]."</th><th>".$this->lang["value"]."</th></tr>", $indent); 3810440ff15Schris ptln(" </thead>", $indent); 3820440ff15Schris ptln(" <tbody>", $indent); 38326fb387bSchris 384*3a97d936SAndreas Gohr $this->htmlInputField( 38564159a61SAndreas Gohr $cmd . "_userid", 38664159a61SAndreas Gohr "userid", 38764159a61SAndreas Gohr $this->lang["user_id"], 38864159a61SAndreas Gohr $user, 389*3a97d936SAndreas Gohr $this->auth->canDo("modLogin"), 39064159a61SAndreas Gohr true, 39164159a61SAndreas Gohr $indent + 6 39264159a61SAndreas Gohr ); 393*3a97d936SAndreas Gohr $this->htmlInputField( 39464159a61SAndreas Gohr $cmd . "_userpass", 39564159a61SAndreas Gohr "userpass", 39664159a61SAndreas Gohr $this->lang["user_pass"], 39764159a61SAndreas Gohr "", 398*3a97d936SAndreas Gohr $this->auth->canDo("modPass"), 39964159a61SAndreas Gohr false, 40064159a61SAndreas Gohr $indent + 6 40164159a61SAndreas Gohr ); 402*3a97d936SAndreas Gohr $this->htmlInputField( 40364159a61SAndreas Gohr $cmd . "_userpass2", 40464159a61SAndreas Gohr "userpass2", 40564159a61SAndreas Gohr $lang["passchk"], 40664159a61SAndreas Gohr "", 407*3a97d936SAndreas Gohr $this->auth->canDo("modPass"), 40864159a61SAndreas Gohr false, 40964159a61SAndreas Gohr $indent + 6 41064159a61SAndreas Gohr ); 411*3a97d936SAndreas Gohr $this->htmlInputField( 41264159a61SAndreas Gohr $cmd . "_username", 41364159a61SAndreas Gohr "username", 41464159a61SAndreas Gohr $this->lang["user_name"], 41564159a61SAndreas Gohr $name, 416*3a97d936SAndreas Gohr $this->auth->canDo("modName"), 41764159a61SAndreas Gohr true, 41864159a61SAndreas Gohr $indent + 6 41964159a61SAndreas Gohr ); 420*3a97d936SAndreas Gohr $this->htmlInputField( 42164159a61SAndreas Gohr $cmd . "_usermail", 42264159a61SAndreas Gohr "usermail", 42364159a61SAndreas Gohr $this->lang["user_mail"], 42464159a61SAndreas Gohr $mail, 425*3a97d936SAndreas Gohr $this->auth->canDo("modMail"), 42664159a61SAndreas Gohr true, 42764159a61SAndreas Gohr $indent + 6 42864159a61SAndreas Gohr ); 429*3a97d936SAndreas Gohr $this->htmlInputField( 43064159a61SAndreas Gohr $cmd . "_usergroups", 43164159a61SAndreas Gohr "usergroups", 43264159a61SAndreas Gohr $this->lang["user_groups"], 43364159a61SAndreas Gohr $groups, 434*3a97d936SAndreas Gohr $this->auth->canDo("modGroups"), 43564159a61SAndreas Gohr false, 43664159a61SAndreas Gohr $indent + 6 43764159a61SAndreas Gohr ); 43826fb387bSchris 439*3a97d936SAndreas Gohr if ($this->auth->canDo("modPass")) { 440ee9498f5SChristopher Smith if ($cmd == 'add') { 441c3f4fb63SGina Haeussge $notes[] = $this->lang['note_pass']; 442ee9498f5SChristopher Smith } 443a6858c6aSchris if ($user) { 444a6858c6aSchris $notes[] = $this->lang['note_notify']; 445a6858c6aSchris } 446a6858c6aSchris 44764159a61SAndreas Gohr ptln("<tr><td><label for=\"".$cmd."_usernotify\" >". 44864159a61SAndreas Gohr $this->lang["user_notify"].": </label></td> 44964159a61SAndreas Gohr <td><input type=\"checkbox\" id=\"".$cmd."_usernotify\" name=\"usernotify\" value=\"1\" /> 45064159a61SAndreas Gohr </td></tr>", $indent); 451a6858c6aSchris } 452a6858c6aSchris 4530440ff15Schris ptln(" </tbody>", $indent); 4540440ff15Schris ptln(" <tbody>", $indent); 4550440ff15Schris ptln(" <tr>", $indent); 4560440ff15Schris ptln(" <td colspan=\"2\">", $indent); 4570440ff15Schris ptln(" <input type=\"hidden\" name=\"do\" value=\"admin\" />", $indent); 4580440ff15Schris ptln(" <input type=\"hidden\" name=\"page\" value=\"usermanager\" />", $indent); 4590440ff15Schris 4600440ff15Schris // save current $user, we need this to access details if the name is changed 4610440ff15Schris if ($user) 462f23f9594SAndreas Gohr ptln(" <input type=\"hidden\" name=\"userid_old\" value=\"".hsc($user)."\" />", $indent); 4630440ff15Schris 464*3a97d936SAndreas Gohr $this->htmlFilterSettings($indent+10); 4650440ff15Schris 466ae614416SAnika Henke ptln(" <button type=\"submit\" name=\"fn[".$cmd."]\">".$this->lang[$cmd]."</button>", $indent); 4670440ff15Schris ptln(" </td>", $indent); 4680440ff15Schris ptln(" </tr>", $indent); 4690440ff15Schris ptln(" </tbody>", $indent); 4700440ff15Schris ptln(" </table>", $indent); 47145c19902SChristopher Smith 47245c19902SChristopher Smith if ($notes) { 47345c19902SChristopher Smith ptln(" <ul class=\"notes\">"); 47445c19902SChristopher Smith foreach ($notes as $note) { 475ae614416SAnika Henke ptln(" <li><span class=\"li\">".$note."</li>", $indent); 47645c19902SChristopher Smith } 47745c19902SChristopher Smith ptln(" </ul>"); 47845c19902SChristopher Smith } 479c7b28ffdSAnika Henke ptln(" </div>", $indent); 4800440ff15Schris ptln("</form>", $indent); 4810440ff15Schris } 4820440ff15Schris 483c5a7c0c6SGerrit Uitslag /** 484c5a7c0c6SGerrit Uitslag * Prints a inputfield 485c5a7c0c6SGerrit Uitslag * 486c5a7c0c6SGerrit Uitslag * @param string $id 487c5a7c0c6SGerrit Uitslag * @param string $name 488c5a7c0c6SGerrit Uitslag * @param string $label 489c5a7c0c6SGerrit Uitslag * @param string $value 490c5a7c0c6SGerrit Uitslag * @param bool $cando whether auth backend is capable to do this action 4919b82d43fSAndreas Gohr * @param bool $required is this field required? 492c5a7c0c6SGerrit Uitslag * @param int $indent 493c5a7c0c6SGerrit Uitslag */ 494*3a97d936SAndreas Gohr protected function htmlInputField($id, $name, $label, $value, $cando, $required, $indent = 0) 495*3a97d936SAndreas Gohr { 4967de12fceSAndreas Gohr $class = $cando ? '' : ' class="disabled"'; 4977de12fceSAndreas Gohr echo str_pad('', $indent); 4987de12fceSAndreas Gohr 499359e9417SChristopher Smith if ($name == 'userpass' || $name == 'userpass2') { 500d796a891SAndreas Gohr $fieldtype = 'password'; 501d796a891SAndreas Gohr $autocomp = 'autocomplete="off"'; 5027b3674bdSChristopher Smith } elseif ($name == 'usermail') { 5037b3674bdSChristopher Smith $fieldtype = 'email'; 5047b3674bdSChristopher Smith $autocomp = ''; 505d796a891SAndreas Gohr } else { 506d796a891SAndreas Gohr $fieldtype = 'text'; 507d796a891SAndreas Gohr $autocomp = ''; 508d796a891SAndreas Gohr } 509f23f9594SAndreas Gohr $value = hsc($value); 510d796a891SAndreas Gohr 5117de12fceSAndreas Gohr echo "<tr $class>"; 5127de12fceSAndreas Gohr echo "<td><label for=\"$id\" >$label: </label></td>"; 5137de12fceSAndreas Gohr echo "<td>"; 5147de12fceSAndreas Gohr if ($cando) { 5159b82d43fSAndreas Gohr $req = ''; 5169b82d43fSAndreas Gohr if ($required) $req = 'required="required"'; 51764159a61SAndreas Gohr echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\" 51864159a61SAndreas Gohr value=\"$value\" class=\"edit\" $autocomp $req />"; 5197de12fceSAndreas Gohr } else { 5207de12fceSAndreas Gohr echo "<input type=\"hidden\" name=\"$name\" value=\"$value\" />"; 52164159a61SAndreas Gohr echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\" 52264159a61SAndreas Gohr value=\"$value\" class=\"edit disabled\" disabled=\"disabled\" />"; 5237de12fceSAndreas Gohr } 5247de12fceSAndreas Gohr echo "</td>"; 5257de12fceSAndreas Gohr echo "</tr>"; 52626fb387bSchris } 52726fb387bSchris 528c5a7c0c6SGerrit Uitslag /** 529c5a7c0c6SGerrit Uitslag * Returns htmlescaped filter value 530c5a7c0c6SGerrit Uitslag * 531c5a7c0c6SGerrit Uitslag * @param string $key name of search field 532c5a7c0c6SGerrit Uitslag * @return string html escaped value 533c5a7c0c6SGerrit Uitslag */ 534*3a97d936SAndreas Gohr protected function htmlFilter($key) 535*3a97d936SAndreas Gohr { 536*3a97d936SAndreas Gohr if (empty($this->filter)) return ''; 537*3a97d936SAndreas Gohr return (isset($this->filter[$key]) ? hsc($this->filter[$key]) : ''); 5380440ff15Schris } 5390440ff15Schris 540c5a7c0c6SGerrit Uitslag /** 541c5a7c0c6SGerrit Uitslag * Print hidden inputs with the current filter values 542c5a7c0c6SGerrit Uitslag * 543c5a7c0c6SGerrit Uitslag * @param int $indent 544c5a7c0c6SGerrit Uitslag */ 545*3a97d936SAndreas Gohr protected function htmlFilterSettings($indent = 0) 546*3a97d936SAndreas Gohr { 5470440ff15Schris 548*3a97d936SAndreas Gohr ptln("<input type=\"hidden\" name=\"start\" value=\"".$this->start."\" />", $indent); 5490440ff15Schris 550*3a97d936SAndreas Gohr foreach ($this->filter as $key => $filter) { 5510440ff15Schris ptln("<input type=\"hidden\" name=\"filter[".$key."]\" value=\"".hsc($filter)."\" />", $indent); 5520440ff15Schris } 5530440ff15Schris } 5540440ff15Schris 555c5a7c0c6SGerrit Uitslag /** 556c5a7c0c6SGerrit Uitslag * Print import form and summary of previous import 557c5a7c0c6SGerrit Uitslag * 558c5a7c0c6SGerrit Uitslag * @param int $indent 559c5a7c0c6SGerrit Uitslag */ 560*3a97d936SAndreas Gohr protected function htmlImportForm($indent = 0) 561*3a97d936SAndreas Gohr { 562ae1afd2fSChristopher Smith global $ID; 563ae1afd2fSChristopher Smith 564ae1afd2fSChristopher Smith $failure_download_link = wl($ID, array('do'=>'admin','page'=>'usermanager','fn[importfails]'=>1)); 565ae1afd2fSChristopher Smith 566ae1afd2fSChristopher Smith ptln('<div class="level2 import_users">', $indent); 567ae1afd2fSChristopher Smith print $this->locale_xhtml('import'); 568ae1afd2fSChristopher Smith ptln(' <form action="'.wl($ID).'" method="post" enctype="multipart/form-data">', $indent); 569ae1afd2fSChristopher Smith formSecurityToken(); 570b59cff8bSGerrit Uitslag ptln(' <label>'.$this->lang['import_userlistcsv'].'<input type="file" name="import" /></label>', $indent); 571ae614416SAnika Henke ptln(' <button type="submit" name="fn[import]">'.$this->lang['import'].'</button>', $indent); 572ae1afd2fSChristopher Smith ptln(' <input type="hidden" name="do" value="admin" />', $indent); 573ae1afd2fSChristopher Smith ptln(' <input type="hidden" name="page" value="usermanager" />', $indent); 574ae1afd2fSChristopher Smith 575*3a97d936SAndreas Gohr $this->htmlFilterSettings($indent+4); 576ae1afd2fSChristopher Smith ptln(' </form>', $indent); 577ae1afd2fSChristopher Smith ptln('</div>'); 578ae1afd2fSChristopher Smith 579ae1afd2fSChristopher Smith // list failures from the previous import 580*3a97d936SAndreas Gohr if ($this->import_failures) { 581*3a97d936SAndreas Gohr $digits = strlen(count($this->import_failures)); 582ae1afd2fSChristopher Smith ptln('<div class="level3 import_failures">', $indent); 583b59cff8bSGerrit Uitslag ptln(' <h3>'.$this->lang['import_header'].'</h3>'); 584ae1afd2fSChristopher Smith ptln(' <table class="import_failures">', $indent); 585ae1afd2fSChristopher Smith ptln(' <thead>', $indent); 586ae1afd2fSChristopher Smith ptln(' <tr>', $indent); 587ae1afd2fSChristopher Smith ptln(' <th class="line">'.$this->lang['line'].'</th>', $indent); 588ae1afd2fSChristopher Smith ptln(' <th class="error">'.$this->lang['error'].'</th>', $indent); 589ae1afd2fSChristopher Smith ptln(' <th class="userid">'.$this->lang['user_id'].'</th>', $indent); 590ae1afd2fSChristopher Smith ptln(' <th class="username">'.$this->lang['user_name'].'</th>', $indent); 591ae1afd2fSChristopher Smith ptln(' <th class="usermail">'.$this->lang['user_mail'].'</th>', $indent); 592ae1afd2fSChristopher Smith ptln(' <th class="usergroups">'.$this->lang['user_groups'].'</th>', $indent); 593ae1afd2fSChristopher Smith ptln(' </tr>', $indent); 594ae1afd2fSChristopher Smith ptln(' </thead>', $indent); 595ae1afd2fSChristopher Smith ptln(' <tbody>', $indent); 596*3a97d936SAndreas Gohr foreach ($this->import_failures as $line => $failure) { 597ae1afd2fSChristopher Smith ptln(' <tr>', $indent); 598ae1afd2fSChristopher Smith ptln(' <td class="lineno"> '.sprintf('%0'.$digits.'d', $line).' </td>', $indent); 599ae1afd2fSChristopher Smith ptln(' <td class="error">' .$failure['error'].' </td>', $indent); 600ae1afd2fSChristopher Smith ptln(' <td class="field userid"> '.hsc($failure['user'][0]).' </td>', $indent); 601ae1afd2fSChristopher Smith ptln(' <td class="field username"> '.hsc($failure['user'][2]).' </td>', $indent); 602ae1afd2fSChristopher Smith ptln(' <td class="field usermail"> '.hsc($failure['user'][3]).' </td>', $indent); 603ae1afd2fSChristopher Smith ptln(' <td class="field usergroups"> '.hsc($failure['user'][4]).' </td>', $indent); 604ae1afd2fSChristopher Smith ptln(' </tr>', $indent); 605ae1afd2fSChristopher Smith } 606ae1afd2fSChristopher Smith ptln(' </tbody>', $indent); 607ae1afd2fSChristopher Smith ptln(' </table>', $indent); 608b59cff8bSGerrit Uitslag ptln(' <p><a href="'.$failure_download_link.'">'.$this->lang['import_downloadfailures'].'</a></p>'); 609ae1afd2fSChristopher Smith ptln('</div>'); 610ae1afd2fSChristopher Smith } 611ae1afd2fSChristopher Smith } 612ae1afd2fSChristopher Smith 613c5a7c0c6SGerrit Uitslag /** 614c5a7c0c6SGerrit Uitslag * Add an user to auth backend 615c5a7c0c6SGerrit Uitslag * 616c5a7c0c6SGerrit Uitslag * @return bool whether succesful 617c5a7c0c6SGerrit Uitslag */ 618*3a97d936SAndreas Gohr protected function addUser() 619*3a97d936SAndreas Gohr { 62000d58927SMichael Hamann global $INPUT; 621634d7150SAndreas Gohr if (!checkSecurityToken()) return false; 622*3a97d936SAndreas Gohr if (!$this->auth->canDo('addUser')) return false; 6230440ff15Schris 624*3a97d936SAndreas Gohr list($user,$pass,$name,$mail,$grps,$passconfirm) = $this->retrieveUser(); 6250440ff15Schris if (empty($user)) return false; 6266733c4d7SChris Smith 627*3a97d936SAndreas Gohr if ($this->auth->canDo('modPass')) { 628c3f4fb63SGina Haeussge if (empty($pass)) { 62900d58927SMichael Hamann if ($INPUT->has('usernotify')) { 6308a285f7fSAndreas Gohr $pass = auth_pwgen($user); 631c3f4fb63SGina Haeussge } else { 63260b9901bSAndreas Gohr msg($this->lang['add_fail'], -1); 63309a5dcd6SMichael Große msg($this->lang['addUser_error_missing_pass'], -1); 63460b9901bSAndreas Gohr return false; 63560b9901bSAndreas Gohr } 636359e9417SChristopher Smith } else { 637*3a97d936SAndreas Gohr if (!$this->verifyPassword($pass, $passconfirm)) { 63809a5dcd6SMichael Große msg($this->lang['add_fail'], -1); 63909a5dcd6SMichael Große msg($this->lang['addUser_error_pass_not_identical'], -1); 640359e9417SChristopher Smith return false; 641359e9417SChristopher Smith } 6426733c4d7SChris Smith } 6436733c4d7SChris Smith } else { 6446733c4d7SChris Smith if (!empty($pass)) { 6456733c4d7SChris Smith msg($this->lang['add_fail'], -1); 64609a5dcd6SMichael Große msg($this->lang['addUser_error_modPass_disabled'], -1); 6476733c4d7SChris Smith return false; 6486733c4d7SChris Smith } 6496733c4d7SChris Smith } 6506733c4d7SChris Smith 651*3a97d936SAndreas Gohr if ($this->auth->canDo('modName')) { 6526733c4d7SChris Smith if (empty($name)) { 6536733c4d7SChris Smith msg($this->lang['add_fail'], -1); 65409a5dcd6SMichael Große msg($this->lang['addUser_error_name_missing'], -1); 6556733c4d7SChris Smith return false; 6566733c4d7SChris Smith } 6576733c4d7SChris Smith } else { 6586733c4d7SChris Smith if (!empty($name)) { 65909a5dcd6SMichael Große msg($this->lang['add_fail'], -1); 66009a5dcd6SMichael Große msg($this->lang['addUser_error_modName_disabled'], -1); 6616733c4d7SChris Smith return false; 6626733c4d7SChris Smith } 6636733c4d7SChris Smith } 6646733c4d7SChris Smith 665*3a97d936SAndreas Gohr if ($this->auth->canDo('modMail')) { 6666733c4d7SChris Smith if (empty($mail)) { 6676733c4d7SChris Smith msg($this->lang['add_fail'], -1); 66809a5dcd6SMichael Große msg($this->lang['addUser_error_mail_missing'], -1); 6696733c4d7SChris Smith return false; 6706733c4d7SChris Smith } 6716733c4d7SChris Smith } else { 6726733c4d7SChris Smith if (!empty($mail)) { 67309a5dcd6SMichael Große msg($this->lang['add_fail'], -1); 67409a5dcd6SMichael Große msg($this->lang['addUser_error_modMail_disabled'], -1); 6756733c4d7SChris Smith return false; 6766733c4d7SChris Smith } 6776733c4d7SChris Smith } 6780440ff15Schris 679*3a97d936SAndreas Gohr if ($ok = $this->auth->triggerUserMod('create', array($user, $pass, $name, $mail, $grps))) { 680a6858c6aSchris msg($this->lang['add_ok'], 1); 681a6858c6aSchris 68200d58927SMichael Hamann if ($INPUT->has('usernotify') && $pass) { 683*3a97d936SAndreas Gohr $this->notifyUser($user, $pass); 684a6858c6aSchris } 685a6858c6aSchris } else { 68660b9901bSAndreas Gohr msg($this->lang['add_fail'], -1); 68709a5dcd6SMichael Große msg($this->lang['addUser_error_create_event_failed'], -1); 688a6858c6aSchris } 689a6858c6aSchris 690a6858c6aSchris return $ok; 6910440ff15Schris } 6920440ff15Schris 6930440ff15Schris /** 694c5a7c0c6SGerrit Uitslag * Delete user from auth backend 695c5a7c0c6SGerrit Uitslag * 696c5a7c0c6SGerrit Uitslag * @return bool whether succesful 6970440ff15Schris */ 698*3a97d936SAndreas Gohr protected function deleteUser() 699*3a97d936SAndreas Gohr { 70000d58927SMichael Hamann global $conf, $INPUT; 7019ec82636SAndreas Gohr 702634d7150SAndreas Gohr if (!checkSecurityToken()) return false; 703*3a97d936SAndreas Gohr if (!$this->auth->canDo('delUser')) return false; 7040440ff15Schris 70500d58927SMichael Hamann $selected = $INPUT->arr('delete'); 70600d58927SMichael Hamann if (empty($selected)) return false; 7070440ff15Schris $selected = array_keys($selected); 7080440ff15Schris 709c9a8f912SMichael Klier if (in_array($_SERVER['REMOTE_USER'], $selected)) { 710c9a8f912SMichael Klier msg("You can't delete yourself!", -1); 711c9a8f912SMichael Klier return false; 712c9a8f912SMichael Klier } 713c9a8f912SMichael Klier 714*3a97d936SAndreas Gohr $count = $this->auth->triggerUserMod('delete', array($selected)); 7150440ff15Schris if ($count == count($selected)) { 7160440ff15Schris $text = str_replace('%d', $count, $this->lang['delete_ok']); 7170440ff15Schris msg("$text.", 1); 7180440ff15Schris } else { 7190440ff15Schris $part1 = str_replace('%d', $count, $this->lang['delete_ok']); 7200440ff15Schris $part2 = str_replace('%d', (count($selected)-$count), $this->lang['delete_fail']); 7210440ff15Schris msg("$part1, $part2", -1); 7220440ff15Schris } 72378c7c8c9Schris 7249ec82636SAndreas Gohr // invalidate all sessions 7259ec82636SAndreas Gohr io_saveFile($conf['cachedir'].'/sessionpurge', time()); 7269ec82636SAndreas Gohr 72778c7c8c9Schris return true; 72878c7c8c9Schris } 72978c7c8c9Schris 73078c7c8c9Schris /** 73178c7c8c9Schris * Edit user (a user has been selected for editing) 732c5a7c0c6SGerrit Uitslag * 733c5a7c0c6SGerrit Uitslag * @param string $param id of the user 734c5a7c0c6SGerrit Uitslag * @return bool whether succesful 73578c7c8c9Schris */ 736*3a97d936SAndreas Gohr protected function editUser($param) 737*3a97d936SAndreas Gohr { 738634d7150SAndreas Gohr if (!checkSecurityToken()) return false; 739*3a97d936SAndreas Gohr if (!$this->auth->canDo('UserMod')) return false; 740*3a97d936SAndreas Gohr $user = $this->auth->cleanUser(preg_replace('/.*[:\/]/', '', $param)); 741*3a97d936SAndreas Gohr $userdata = $this->auth->getUserData($user); 74278c7c8c9Schris 74378c7c8c9Schris // no user found? 74478c7c8c9Schris if (!$userdata) { 74578c7c8c9Schris msg($this->lang['edit_usermissing'], -1); 74678c7c8c9Schris return false; 74778c7c8c9Schris } 74878c7c8c9Schris 749*3a97d936SAndreas Gohr $this->edit_user = $user; 750*3a97d936SAndreas Gohr $this->edit_userdata = $userdata; 75178c7c8c9Schris 75278c7c8c9Schris return true; 7530440ff15Schris } 7540440ff15Schris 7550440ff15Schris /** 756c5a7c0c6SGerrit Uitslag * Modify user in the auth backend (modified user data has been recieved) 757c5a7c0c6SGerrit Uitslag * 758c5a7c0c6SGerrit Uitslag * @return bool whether succesful 7590440ff15Schris */ 760*3a97d936SAndreas Gohr protected function modifyUser() 761*3a97d936SAndreas Gohr { 76200d58927SMichael Hamann global $conf, $INPUT; 7639ec82636SAndreas Gohr 764634d7150SAndreas Gohr if (!checkSecurityToken()) return false; 765*3a97d936SAndreas Gohr if (!$this->auth->canDo('UserMod')) return false; 7660440ff15Schris 76726fb387bSchris // get currently valid user data 768*3a97d936SAndreas Gohr $olduser = $this->auth->cleanUser(preg_replace('/.*[:\/]/', '', $INPUT->str('userid_old'))); 769*3a97d936SAndreas Gohr $oldinfo = $this->auth->getUserData($olduser); 770073766c6Smatthiasgrimm 77126fb387bSchris // get new user data subject to change 772*3a97d936SAndreas Gohr list($newuser,$newpass,$newname,$newmail,$newgrps,$passconfirm) = $this->retrieveUser(); 773073766c6Smatthiasgrimm if (empty($newuser)) return false; 7740440ff15Schris 7750440ff15Schris $changes = array(); 776073766c6Smatthiasgrimm if ($newuser != $olduser) { 777*3a97d936SAndreas Gohr if (!$this->auth->canDo('modLogin')) { // sanity check, shouldn't be possible 77826fb387bSchris msg($this->lang['update_fail'], -1); 77926fb387bSchris return false; 78026fb387bSchris } 78126fb387bSchris 78226fb387bSchris // check if $newuser already exists 783*3a97d936SAndreas Gohr if ($this->auth->getUserData($newuser)) { 784073766c6Smatthiasgrimm msg(sprintf($this->lang['update_exists'], $newuser), -1); 785a6858c6aSchris $re_edit = true; 7860440ff15Schris } else { 787073766c6Smatthiasgrimm $changes['user'] = $newuser; 7880440ff15Schris } 78993eefc2fSAndreas Gohr } 790*3a97d936SAndreas Gohr if ($this->auth->canDo('modPass')) { 7912400ddcbSChristopher Smith if ($newpass || $passconfirm) { 792*3a97d936SAndreas Gohr if ($this->verifyPassword($newpass, $passconfirm)) { 793359e9417SChristopher Smith $changes['pass'] = $newpass; 794359e9417SChristopher Smith } else { 795359e9417SChristopher Smith return false; 796359e9417SChristopher Smith } 797359e9417SChristopher Smith } else { 798359e9417SChristopher Smith // no new password supplied, check if we need to generate one (or it stays unchanged) 799359e9417SChristopher Smith if ($INPUT->has('usernotify')) { 800359e9417SChristopher Smith $changes['pass'] = auth_pwgen($olduser); 801359e9417SChristopher Smith } 802359e9417SChristopher Smith } 8030440ff15Schris } 8040440ff15Schris 805*3a97d936SAndreas Gohr if (!empty($newname) && $this->auth->canDo('modName') && $newname != $oldinfo['name']) { 806073766c6Smatthiasgrimm $changes['name'] = $newname; 80740d72af6SChristopher Smith } 808*3a97d936SAndreas Gohr if (!empty($newmail) && $this->auth->canDo('modMail') && $newmail != $oldinfo['mail']) { 809073766c6Smatthiasgrimm $changes['mail'] = $newmail; 81040d72af6SChristopher Smith } 811*3a97d936SAndreas Gohr if (!empty($newgrps) && $this->auth->canDo('modGroups') && $newgrps != $oldinfo['grps']) { 812073766c6Smatthiasgrimm $changes['grps'] = $newgrps; 81340d72af6SChristopher Smith } 8140440ff15Schris 815*3a97d936SAndreas Gohr if ($ok = $this->auth->triggerUserMod('modify', array($olduser, $changes))) { 8160440ff15Schris msg($this->lang['update_ok'], 1); 817a6858c6aSchris 8186ed3476bSChristopher Smith if ($INPUT->has('usernotify') && !empty($changes['pass'])) { 819a6858c6aSchris $notify = empty($changes['user']) ? $olduser : $newuser; 820*3a97d936SAndreas Gohr $this->notifyUser($notify, $changes['pass']); 821a6858c6aSchris } 822a6858c6aSchris 8239ec82636SAndreas Gohr // invalidate all sessions 8249ec82636SAndreas Gohr io_saveFile($conf['cachedir'].'/sessionpurge', time()); 8250440ff15Schris } else { 8260440ff15Schris msg($this->lang['update_fail'], -1); 8270440ff15Schris } 82878c7c8c9Schris 829a6858c6aSchris if (!empty($re_edit)) { 830*3a97d936SAndreas Gohr $this->editUser($olduser); 8310440ff15Schris } 8320440ff15Schris 833a6858c6aSchris return $ok; 834a6858c6aSchris } 835a6858c6aSchris 836a6858c6aSchris /** 837c5a7c0c6SGerrit Uitslag * Send password change notification email 838c5a7c0c6SGerrit Uitslag * 839c5a7c0c6SGerrit Uitslag * @param string $user id of user 840c5a7c0c6SGerrit Uitslag * @param string $password plain text 841c5a7c0c6SGerrit Uitslag * @param bool $status_alert whether status alert should be shown 842c5a7c0c6SGerrit Uitslag * @return bool whether succesful 843a6858c6aSchris */ 844*3a97d936SAndreas Gohr protected function notifyUser($user, $password, $status_alert = true) 845*3a97d936SAndreas Gohr { 846a6858c6aSchris 847a6858c6aSchris if ($sent = auth_sendPassword($user, $password)) { 848328143f8SChristopher Smith if ($status_alert) { 849a6858c6aSchris msg($this->lang['notify_ok'], 1); 850328143f8SChristopher Smith } 851a6858c6aSchris } else { 852328143f8SChristopher Smith if ($status_alert) { 853a6858c6aSchris msg($this->lang['notify_fail'], -1); 854a6858c6aSchris } 855328143f8SChristopher Smith } 856a6858c6aSchris 857a6858c6aSchris return $sent; 858a6858c6aSchris } 859a6858c6aSchris 860a6858c6aSchris /** 861359e9417SChristopher Smith * Verify password meets minimum requirements 862359e9417SChristopher Smith * :TODO: extend to support password strength 863359e9417SChristopher Smith * 864359e9417SChristopher Smith * @param string $password candidate string for new password 865359e9417SChristopher Smith * @param string $confirm repeated password for confirmation 866359e9417SChristopher Smith * @return bool true if meets requirements, false otherwise 867359e9417SChristopher Smith */ 868*3a97d936SAndreas Gohr protected function verifyPassword($password, $confirm) 869*3a97d936SAndreas Gohr { 870be9008d3SChristopher Smith global $lang; 871359e9417SChristopher Smith 8722400ddcbSChristopher Smith if (empty($password) && empty($confirm)) { 873359e9417SChristopher Smith return false; 874359e9417SChristopher Smith } 875359e9417SChristopher Smith 876359e9417SChristopher Smith if ($password !== $confirm) { 877be9008d3SChristopher Smith msg($lang['regbadpass'], -1); 878359e9417SChristopher Smith return false; 879359e9417SChristopher Smith } 880359e9417SChristopher Smith 881359e9417SChristopher Smith // :TODO: test password for required strength 882359e9417SChristopher Smith 883359e9417SChristopher Smith // if we make it this far the password is good 884359e9417SChristopher Smith return true; 885359e9417SChristopher Smith } 886359e9417SChristopher Smith 887359e9417SChristopher Smith /** 888c5a7c0c6SGerrit Uitslag * Retrieve & clean user data from the form 889a6858c6aSchris * 890c5a7c0c6SGerrit Uitslag * @param bool $clean whether the cleanUser method of the authentication backend is applied 891a6858c6aSchris * @return array (user, password, full name, email, array(groups)) 8920440ff15Schris */ 893*3a97d936SAndreas Gohr protected function retrieveUser($clean = true) 894*3a97d936SAndreas Gohr { 895c5a7c0c6SGerrit Uitslag /** @var DokuWiki_Auth_Plugin $auth */ 8967441e340SAndreas Gohr global $auth; 897fbfbbe8aSHakan Sandell global $INPUT; 8980440ff15Schris 89959bc3b48SGerrit Uitslag $user = array(); 900fbfbbe8aSHakan Sandell $user[0] = ($clean) ? $auth->cleanUser($INPUT->str('userid')) : $INPUT->str('userid'); 901fbfbbe8aSHakan Sandell $user[1] = $INPUT->str('userpass'); 902fbfbbe8aSHakan Sandell $user[2] = $INPUT->str('username'); 903fbfbbe8aSHakan Sandell $user[3] = $INPUT->str('usermail'); 904fbfbbe8aSHakan Sandell $user[4] = explode(',', $INPUT->str('usergroups')); 905359e9417SChristopher Smith $user[5] = $INPUT->str('userpass2'); // repeated password for confirmation 9060440ff15Schris 9077441e340SAndreas Gohr $user[4] = array_map('trim', $user[4]); 9087441e340SAndreas Gohr if ($clean) $user[4] = array_map(array($auth,'cleanGroup'), $user[4]); 9097441e340SAndreas Gohr $user[4] = array_filter($user[4]); 9107441e340SAndreas Gohr $user[4] = array_unique($user[4]); 9117441e340SAndreas Gohr if (!count($user[4])) $user[4] = null; 9120440ff15Schris 9130440ff15Schris return $user; 9140440ff15Schris } 9150440ff15Schris 916c5a7c0c6SGerrit Uitslag /** 917c5a7c0c6SGerrit Uitslag * Set the filter with the current search terms or clear the filter 918c5a7c0c6SGerrit Uitslag * 919c5a7c0c6SGerrit Uitslag * @param string $op 'new' or 'clear' 920c5a7c0c6SGerrit Uitslag */ 921*3a97d936SAndreas Gohr protected function setFilter($op) 922*3a97d936SAndreas Gohr { 9230440ff15Schris 924*3a97d936SAndreas Gohr $this->filter = array(); 9250440ff15Schris 9260440ff15Schris if ($op == 'new') { 927*3a97d936SAndreas Gohr list($user,/* $pass */,$name,$mail,$grps) = $this->retrieveUser(false); 9280440ff15Schris 929*3a97d936SAndreas Gohr if (!empty($user)) $this->filter['user'] = $user; 930*3a97d936SAndreas Gohr if (!empty($name)) $this->filter['name'] = $name; 931*3a97d936SAndreas Gohr if (!empty($mail)) $this->filter['mail'] = $mail; 932*3a97d936SAndreas Gohr if (!empty($grps)) $this->filter['grps'] = join('|', $grps); 9330440ff15Schris } 9340440ff15Schris } 9350440ff15Schris 936c5a7c0c6SGerrit Uitslag /** 937c5a7c0c6SGerrit Uitslag * Get the current search terms 938c5a7c0c6SGerrit Uitslag * 939c5a7c0c6SGerrit Uitslag * @return array 940c5a7c0c6SGerrit Uitslag */ 941*3a97d936SAndreas Gohr protected function retrieveFilter() 942*3a97d936SAndreas Gohr { 943fbfbbe8aSHakan Sandell global $INPUT; 9440440ff15Schris 945fbfbbe8aSHakan Sandell $t_filter = $INPUT->arr('filter'); 9460440ff15Schris 9470440ff15Schris // messy, but this way we ensure we aren't getting any additional crap from malicious users 9480440ff15Schris $filter = array(); 9490440ff15Schris 9500440ff15Schris if (isset($t_filter['user'])) $filter['user'] = $t_filter['user']; 9510440ff15Schris if (isset($t_filter['name'])) $filter['name'] = $t_filter['name']; 9520440ff15Schris if (isset($t_filter['mail'])) $filter['mail'] = $t_filter['mail']; 9530440ff15Schris if (isset($t_filter['grps'])) $filter['grps'] = $t_filter['grps']; 9540440ff15Schris 9550440ff15Schris return $filter; 9560440ff15Schris } 9570440ff15Schris 958c5a7c0c6SGerrit Uitslag /** 959c5a7c0c6SGerrit Uitslag * Validate and improve the pagination values 960c5a7c0c6SGerrit Uitslag */ 961*3a97d936SAndreas Gohr protected function validatePagination() 962*3a97d936SAndreas Gohr { 9630440ff15Schris 964*3a97d936SAndreas Gohr if ($this->start >= $this->users_total) { 965*3a97d936SAndreas Gohr $this->start = $this->users_total - $this->pagesize; 9660440ff15Schris } 967*3a97d936SAndreas Gohr if ($this->start < 0) $this->start = 0; 9680440ff15Schris 969*3a97d936SAndreas Gohr $this->last = min($this->users_total, $this->start + $this->pagesize); 9700440ff15Schris } 9710440ff15Schris 972c5a7c0c6SGerrit Uitslag /** 973c5a7c0c6SGerrit Uitslag * Return an array of strings to enable/disable pagination buttons 974c5a7c0c6SGerrit Uitslag * 975c5a7c0c6SGerrit Uitslag * @return array with enable/disable attributes 9760440ff15Schris */ 977*3a97d936SAndreas Gohr protected function pagination() 978*3a97d936SAndreas Gohr { 9790440ff15Schris 98051d94d49Schris $disabled = 'disabled="disabled"'; 98151d94d49Schris 98259bc3b48SGerrit Uitslag $buttons = array(); 983*3a97d936SAndreas Gohr $buttons['start'] = $buttons['prev'] = ($this->start == 0) ? $disabled : ''; 98451d94d49Schris 985*3a97d936SAndreas Gohr if ($this->users_total == -1) { 98651d94d49Schris $buttons['last'] = $disabled; 98751d94d49Schris $buttons['next'] = ''; 98851d94d49Schris } else { 98964159a61SAndreas Gohr $buttons['last'] = $buttons['next'] = 990*3a97d936SAndreas Gohr (($this->start + $this->pagesize) >= $this->users_total) ? $disabled : ''; 99151d94d49Schris } 9920440ff15Schris 993*3a97d936SAndreas Gohr if ($this->lastdisabled) { 994462e9e37SMichael Große $buttons['last'] = $disabled; 995462e9e37SMichael Große } 996462e9e37SMichael Große 9970440ff15Schris return $buttons; 9980440ff15Schris } 9995c967d3dSChristopher Smith 1000c5a7c0c6SGerrit Uitslag /** 1001c5a7c0c6SGerrit Uitslag * Export a list of users in csv format using the current filter criteria 10025c967d3dSChristopher Smith */ 1003*3a97d936SAndreas Gohr protected function exportCSV() 1004*3a97d936SAndreas Gohr { 10055c967d3dSChristopher Smith // list of users for export - based on current filter criteria 1006*3a97d936SAndreas Gohr $user_list = $this->auth->retrieveUsers(0, 0, $this->filter); 10075c967d3dSChristopher Smith $column_headings = array( 10085c967d3dSChristopher Smith $this->lang["user_id"], 10095c967d3dSChristopher Smith $this->lang["user_name"], 10105c967d3dSChristopher Smith $this->lang["user_mail"], 10115c967d3dSChristopher Smith $this->lang["user_groups"] 10125c967d3dSChristopher Smith ); 10135c967d3dSChristopher Smith 10145c967d3dSChristopher Smith // ============================================================================================== 10155c967d3dSChristopher Smith // GENERATE OUTPUT 10165c967d3dSChristopher Smith // normal headers for downloading... 10175c967d3dSChristopher Smith header('Content-type: text/csv;charset=utf-8'); 10185c967d3dSChristopher Smith header('Content-Disposition: attachment; filename="wikiusers.csv"'); 10195c967d3dSChristopher Smith# // for debugging assistance, send as text plain to the browser 10205c967d3dSChristopher Smith# header('Content-type: text/plain;charset=utf-8'); 10215c967d3dSChristopher Smith 10225c967d3dSChristopher Smith // output the csv 10235c967d3dSChristopher Smith $fd = fopen('php://output', 'w'); 10245c967d3dSChristopher Smith fputcsv($fd, $column_headings); 10255c967d3dSChristopher Smith foreach ($user_list as $user => $info) { 10265c967d3dSChristopher Smith $line = array($user, $info['name'], $info['mail'], join(',', $info['grps'])); 10275c967d3dSChristopher Smith fputcsv($fd, $line); 10285c967d3dSChristopher Smith } 10295c967d3dSChristopher Smith fclose($fd); 1030*3a97d936SAndreas Gohr if (defined('DOKU_UNITTEST')) { 1031*3a97d936SAndreas Gohr return; 1032*3a97d936SAndreas Gohr } 1033b2c01466SChristopher Smith 10345c967d3dSChristopher Smith die; 10355c967d3dSChristopher Smith } 1036ae1afd2fSChristopher Smith 1037c5a7c0c6SGerrit Uitslag /** 1038c5a7c0c6SGerrit Uitslag * Import a file of users in csv format 1039ae1afd2fSChristopher Smith * 1040ae1afd2fSChristopher Smith * csv file should have 4 columns, user_id, full name, email, groups (comma separated) 1041c5a7c0c6SGerrit Uitslag * 10425ba64050SChristopher Smith * @return bool whether successful 1043ae1afd2fSChristopher Smith */ 1044*3a97d936SAndreas Gohr protected function importCSV() 1045*3a97d936SAndreas Gohr { 1046ae1afd2fSChristopher Smith // check we are allowed to add users 1047ae1afd2fSChristopher Smith if (!checkSecurityToken()) return false; 1048*3a97d936SAndreas Gohr if (!$this->auth->canDo('addUser')) return false; 1049ae1afd2fSChristopher Smith 1050ae1afd2fSChristopher Smith // check file uploaded ok. 1051*3a97d936SAndreas Gohr if (empty($_FILES['import']['size']) || 1052*3a97d936SAndreas Gohr !empty($_FILES['import']['error']) && $this->isUploadedFile($_FILES['import']['tmp_name']) 105364159a61SAndreas Gohr ) { 1054ae1afd2fSChristopher Smith msg($this->lang['import_error_upload'], -1); 1055ae1afd2fSChristopher Smith return false; 1056ae1afd2fSChristopher Smith } 1057ae1afd2fSChristopher Smith // retrieve users from the file 1058*3a97d936SAndreas Gohr $this->import_failures = array(); 1059ae1afd2fSChristopher Smith $import_success_count = 0; 1060ae1afd2fSChristopher Smith $import_fail_count = 0; 1061ae1afd2fSChristopher Smith $line = 0; 1062ae1afd2fSChristopher Smith $fd = fopen($_FILES['import']['tmp_name'], 'r'); 1063ae1afd2fSChristopher Smith if ($fd) { 1064ae1afd2fSChristopher Smith while ($csv = fgets($fd)) { 1065efcec72bSChristopher Smith if (!utf8_check($csv)) { 1066efcec72bSChristopher Smith $csv = utf8_encode($csv); 1067efcec72bSChristopher Smith } 1068d0c0a5c4SAnika Henke $raw = str_getcsv($csv); 1069ae1afd2fSChristopher Smith $error = ''; // clean out any errors from the previous line 1070ae1afd2fSChristopher Smith // data checks... 1071ae1afd2fSChristopher Smith if (1 == ++$line) { 1072ae1afd2fSChristopher Smith if ($raw[0] == 'user_id' || $raw[0] == $this->lang['user_id']) continue; // skip headers 1073ae1afd2fSChristopher Smith } 1074ae1afd2fSChristopher Smith if (count($raw) < 4) { // need at least four fields 1075ae1afd2fSChristopher Smith $import_fail_count++; 1076ae1afd2fSChristopher Smith $error = sprintf($this->lang['import_error_fields'], count($raw)); 1077*3a97d936SAndreas Gohr $this->import_failures[$line] = array('error' => $error, 'user' => $raw, 'orig' => $csv); 1078ae1afd2fSChristopher Smith continue; 1079ae1afd2fSChristopher Smith } 1080ae1afd2fSChristopher Smith array_splice($raw, 1, 0, auth_pwgen()); // splice in a generated password 1081*3a97d936SAndreas Gohr $clean = $this->cleanImportUser($raw, $error); 1082*3a97d936SAndreas Gohr if ($clean && $this->importUser($clean, $error)) { 1083*3a97d936SAndreas Gohr $sent = $this->notifyUser($clean[0], $clean[1], false); 1084328143f8SChristopher Smith if (!$sent) { 1085328143f8SChristopher Smith msg(sprintf($this->lang['import_notify_fail'], $clean[0], $clean[3]), -1); 1086328143f8SChristopher Smith } 1087ae1afd2fSChristopher Smith $import_success_count++; 1088ae1afd2fSChristopher Smith } else { 1089ae1afd2fSChristopher Smith $import_fail_count++; 1090e73725baSChristopher Smith array_splice($raw, 1, 1); // remove the spliced in password 1091*3a97d936SAndreas Gohr $this->import_failures[$line] = array('error' => $error, 'user' => $raw, 'orig' => $csv); 1092ae1afd2fSChristopher Smith } 1093ae1afd2fSChristopher Smith } 109464159a61SAndreas Gohr msg( 109564159a61SAndreas Gohr sprintf( 109664159a61SAndreas Gohr $this->lang['import_success_count'], 109764159a61SAndreas Gohr ($import_success_count + $import_fail_count), 109864159a61SAndreas Gohr $import_success_count 109964159a61SAndreas Gohr ), 110064159a61SAndreas Gohr ($import_success_count ? 1 : -1) 110164159a61SAndreas Gohr ); 1102ae1afd2fSChristopher Smith if ($import_fail_count) { 1103ae1afd2fSChristopher Smith msg(sprintf($this->lang['import_failure_count'], $import_fail_count), -1); 1104ae1afd2fSChristopher Smith } 1105ae1afd2fSChristopher Smith } else { 1106ae1afd2fSChristopher Smith msg($this->lang['import_error_readfail'], -1); 1107ae1afd2fSChristopher Smith } 1108ae1afd2fSChristopher Smith 1109ae1afd2fSChristopher Smith // save import failures into the session 1110ae1afd2fSChristopher Smith if (!headers_sent()) { 1111ae1afd2fSChristopher Smith session_start(); 1112*3a97d936SAndreas Gohr $_SESSION['import_failures'] = $this->import_failures; 1113ae1afd2fSChristopher Smith session_write_close(); 1114ae1afd2fSChristopher Smith } 1115c5a7c0c6SGerrit Uitslag return true; 1116ae1afd2fSChristopher Smith } 1117ae1afd2fSChristopher Smith 1118c5a7c0c6SGerrit Uitslag /** 1119786dfb0eSGerrit Uitslag * Returns cleaned user data 1120c5a7c0c6SGerrit Uitslag * 1121c5a7c0c6SGerrit Uitslag * @param array $candidate raw values of line from input file 1122253d4b48SGerrit Uitslag * @param string $error 1123253d4b48SGerrit Uitslag * @return array|false cleaned data or false 1124c5a7c0c6SGerrit Uitslag */ 1125*3a97d936SAndreas Gohr protected function cleanImportUser($candidate, & $error) 1126*3a97d936SAndreas Gohr { 1127ae1afd2fSChristopher Smith global $INPUT; 1128ae1afd2fSChristopher Smith 1129*3a97d936SAndreas Gohr // FIXME kludgy .... 1130ae1afd2fSChristopher Smith $INPUT->set('userid', $candidate[0]); 1131ae1afd2fSChristopher Smith $INPUT->set('userpass', $candidate[1]); 1132ae1afd2fSChristopher Smith $INPUT->set('username', $candidate[2]); 1133ae1afd2fSChristopher Smith $INPUT->set('usermail', $candidate[3]); 1134ae1afd2fSChristopher Smith $INPUT->set('usergroups', $candidate[4]); 1135ae1afd2fSChristopher Smith 1136*3a97d936SAndreas Gohr $cleaned = $this->retrieveUser(); 113759bc3b48SGerrit Uitslag list($user,/* $pass */,$name,$mail,/* $grps */) = $cleaned; 1138ae1afd2fSChristopher Smith if (empty($user)) { 1139ae1afd2fSChristopher Smith $error = $this->lang['import_error_baduserid']; 1140ae1afd2fSChristopher Smith return false; 1141ae1afd2fSChristopher Smith } 1142ae1afd2fSChristopher Smith 1143ae1afd2fSChristopher Smith // no need to check password, handled elsewhere 1144ae1afd2fSChristopher Smith 1145*3a97d936SAndreas Gohr if (!($this->auth->canDo('modName') xor empty($name))) { 1146ae1afd2fSChristopher Smith $error = $this->lang['import_error_badname']; 1147ae1afd2fSChristopher Smith return false; 1148ae1afd2fSChristopher Smith } 1149ae1afd2fSChristopher Smith 1150*3a97d936SAndreas Gohr if ($this->auth->canDo('modMail')) { 1151328143f8SChristopher Smith if (empty($mail) || !mail_isvalid($mail)) { 1152ae1afd2fSChristopher Smith $error = $this->lang['import_error_badmail']; 1153ae1afd2fSChristopher Smith return false; 1154ae1afd2fSChristopher Smith } 1155328143f8SChristopher Smith } else { 1156328143f8SChristopher Smith if (!empty($mail)) { 1157328143f8SChristopher Smith $error = $this->lang['import_error_badmail']; 1158328143f8SChristopher Smith return false; 1159328143f8SChristopher Smith } 1160328143f8SChristopher Smith } 1161ae1afd2fSChristopher Smith 1162ae1afd2fSChristopher Smith return $cleaned; 1163ae1afd2fSChristopher Smith } 1164ae1afd2fSChristopher Smith 1165c5a7c0c6SGerrit Uitslag /** 1166c5a7c0c6SGerrit Uitslag * Adds imported user to auth backend 1167c5a7c0c6SGerrit Uitslag * 1168c5a7c0c6SGerrit Uitslag * Required a check of canDo('addUser') before 1169c5a7c0c6SGerrit Uitslag * 1170c5a7c0c6SGerrit Uitslag * @param array $user data of user 1171c5a7c0c6SGerrit Uitslag * @param string &$error reference catched error message 11725ba64050SChristopher Smith * @return bool whether successful 1173c5a7c0c6SGerrit Uitslag */ 1174*3a97d936SAndreas Gohr protected function importUser($user, &$error) 1175*3a97d936SAndreas Gohr { 1176*3a97d936SAndreas Gohr if (!$this->auth->triggerUserMod('create', $user)) { 1177ae1afd2fSChristopher Smith $error = $this->lang['import_error_create']; 1178ae1afd2fSChristopher Smith return false; 1179ae1afd2fSChristopher Smith } 1180ae1afd2fSChristopher Smith 1181ae1afd2fSChristopher Smith return true; 1182ae1afd2fSChristopher Smith } 1183ae1afd2fSChristopher Smith 1184c5a7c0c6SGerrit Uitslag /** 1185c5a7c0c6SGerrit Uitslag * Downloads failures as csv file 1186c5a7c0c6SGerrit Uitslag */ 1187*3a97d936SAndreas Gohr protected function downloadImportFailures() 1188*3a97d936SAndreas Gohr { 1189ae1afd2fSChristopher Smith 1190ae1afd2fSChristopher Smith // ============================================================================================== 1191ae1afd2fSChristopher Smith // GENERATE OUTPUT 1192ae1afd2fSChristopher Smith // normal headers for downloading... 1193ae1afd2fSChristopher Smith header('Content-type: text/csv;charset=utf-8'); 1194ae1afd2fSChristopher Smith header('Content-Disposition: attachment; filename="importfails.csv"'); 1195ae1afd2fSChristopher Smith# // for debugging assistance, send as text plain to the browser 1196ae1afd2fSChristopher Smith# header('Content-type: text/plain;charset=utf-8'); 1197ae1afd2fSChristopher Smith 1198ae1afd2fSChristopher Smith // output the csv 1199ae1afd2fSChristopher Smith $fd = fopen('php://output', 'w'); 1200*3a97d936SAndreas Gohr foreach ($this->import_failures as $fail) { 1201ae1afd2fSChristopher Smith fputs($fd, $fail['orig']); 1202ae1afd2fSChristopher Smith } 1203ae1afd2fSChristopher Smith fclose($fd); 1204ae1afd2fSChristopher Smith die; 1205ae1afd2fSChristopher Smith } 1206ae1afd2fSChristopher Smith 1207b2c01466SChristopher Smith /** 1208b2c01466SChristopher Smith * wrapper for is_uploaded_file to facilitate overriding by test suite 1209253d4b48SGerrit Uitslag * 1210253d4b48SGerrit Uitslag * @param string $file filename 1211253d4b48SGerrit Uitslag * @return bool 1212b2c01466SChristopher Smith */ 1213*3a97d936SAndreas Gohr protected function isUploadedFile($file) 1214*3a97d936SAndreas Gohr { 1215b2c01466SChristopher Smith return is_uploaded_file($file); 1216b2c01466SChristopher Smith } 12170440ff15Schris} 1218