Completed
Push — nozlib ( a04611...a8d259 )
by Andreas
11:20 queued 05:17
created

admin_plugin_usermanager::_htmlInputField()   C

Complexity

Conditions 7
Paths 18

Size

Total Lines 30
Code Lines 25

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 30
rs 6.7272
cc 7
eloc 25
nc 18
nop 7
1
<?php
2
/*
3
 *  User Manager
4
 *
5
 *  Dokuwiki Admin Plugin
6
 *
7
 *  This version of the user manager has been modified to only work with
8
 *  objectified version of auth system
9
 *
10
 *  @author  neolao <[email protected]>
11
 *  @author  Chris Smith <[email protected]>
12
 */
13
// must be run within Dokuwiki
14
if(!defined('DOKU_INC')) die();
15
16
if(!defined('DOKU_PLUGIN_IMAGES')) define('DOKU_PLUGIN_IMAGES',DOKU_BASE.'lib/plugins/usermanager/images/');
17
18
/**
19
 * All DokuWiki plugins to extend the admin function
20
 * need to inherit from this class
21
 */
22
class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
23
24
    protected $_auth = null;        // auth object
25
    protected $_user_total = 0;     // number of registered users
26
    protected $_filter = array();   // user selection filter(s)
27
    protected $_start = 0;          // index of first user to be displayed
28
    protected $_last = 0;           // index of the last user to be displayed
29
    protected $_pagesize = 20;      // number of users to list on one page
30
    protected $_edit_user = '';     // set to user selected for editing
31
    protected $_edit_userdata = array();
32
    protected $_disabled = '';      // if disabled set to explanatory string
33
    protected $_import_failures = array();
34
    protected $_lastdisabled = false; // set to true if last user is unknown and last button is hence buggy
35
36
    /**
37
     * Constructor
38
     */
39
    public function __construct(){
40
        /** @var DokuWiki_Auth_Plugin $auth */
41
        global $auth;
42
43
        $this->setupLocale();
44
45
        if (!isset($auth)) {
46
            $this->_disabled = $this->lang['noauth'];
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
47
        } else if (!$auth->canDo('getUsers')) {
48
            $this->_disabled = $this->lang['nosupport'];
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
49
        } else {
50
51
            // we're good to go
52
            $this->_auth = & $auth;
53
54
        }
55
56
        // attempt to retrieve any import failures from the session
57
        if (!empty($_SESSION['import_failures'])){
58
            $this->_import_failures = $_SESSION['import_failures'];
59
        }
60
    }
61
62
    /**
63
     * Return prompt for admin menu
64
     *
65
     * @param string $language
66
     * @return string
67
     */
68
    public function getMenuText($language) {
69
70
        if (!is_null($this->_auth))
71
          return parent::getMenuText($language);
72
73
        return $this->getLang('menu').' '.$this->_disabled;
74
    }
75
76
    /**
77
     * return sort order for position in admin menu
78
     *
79
     * @return int
80
     */
81
    public function getMenuSort() {
82
        return 2;
83
    }
84
85
    /**
86
     * @return int current start value for pageination
87
     */
88
    public function getStart() {
89
        return $this->_start;
90
    }
91
92
    /**
93
     * @return int number of users per page
94
     */
95
    public function getPagesize() {
96
        return $this->_pagesize;
97
    }
98
99
    /**
100
     * @param boolean $lastdisabled
101
     */
102
    public function setLastdisabled($lastdisabled) {
103
        $this->_lastdisabled = $lastdisabled;
104
    }
105
106
    /**
107
     * Handle user request
108
     *
109
     * @return bool
110
     */
111
    public function handle() {
112
        global $INPUT;
113
        if (is_null($this->_auth)) return false;
114
115
        // extract the command and any specific parameters
116
        // submit button name is of the form - fn[cmd][param(s)]
117
        $fn   = $INPUT->param('fn');
118
119
        if (is_array($fn)) {
120
            $cmd = key($fn);
121
            $param = is_array($fn[$cmd]) ? key($fn[$cmd]) : null;
122
        } else {
123
            $cmd = $fn;
124
            $param = null;
125
        }
126
127
        if ($cmd != "search") {
128
            $this->_start = $INPUT->int('start', 0);
129
            $this->_filter = $this->_retrieveFilter();
130
        }
131
132
        switch($cmd){
133
            case "add"    : $this->_addUser(); break;
134
            case "delete" : $this->_deleteUser(); break;
135
            case "modify" : $this->_modifyUser(); break;
136
            case "edit"   : $this->_editUser($param); break;
137
            case "search" : $this->_setFilter($param);
138
                            $this->_start = 0;
139
                            break;
140
            case "export" : $this->_export(); break;
141
            case "import" : $this->_import(); break;
142
            case "importfails" : $this->_downloadImportFailures(); break;
143
        }
144
145
        $this->_user_total = $this->_auth->canDo('getUserCount') ? $this->_auth->getUserCount($this->_filter) : -1;
146
147
        // page handling
148
        switch($cmd){
149
            case 'start' : $this->_start = 0; break;
150
            case 'prev'  : $this->_start -= $this->_pagesize; break;
151
            case 'next'  : $this->_start += $this->_pagesize; break;
152
            case 'last'  : $this->_start = $this->_user_total; break;
153
        }
154
        $this->_validatePagination();
155
        return true;
156
    }
157
158
    /**
159
     * Output appropriate html
160
     *
161
     * @return bool
162
     */
163
    public function html() {
164
        global $ID;
165
166
        if(is_null($this->_auth)) {
167
            print $this->lang['badauth'];
168
            return false;
169
        }
170
171
        $user_list = $this->_auth->retrieveUsers($this->_start, $this->_pagesize, $this->_filter);
172
173
        $page_buttons = $this->_pagination();
174
        $delete_disable = $this->_auth->canDo('delUser') ? '' : 'disabled="disabled"';
175
176
        $editable = $this->_auth->canDo('UserMod');
177
        $export_label = empty($this->_filter) ? $this->lang['export_all'] : $this->lang['export_filtered'];
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
178
179
        print $this->locale_xhtml('intro');
180
        print $this->locale_xhtml('list');
181
182
        ptln("<div id=\"user__manager\">");
183
        ptln("<div class=\"level2\">");
184
185
        if ($this->_user_total > 0) {
186
            ptln("<p>".sprintf($this->lang['summary'],$this->_start+1,$this->_last,$this->_user_total,$this->_auth->getUserCount())."</p>");
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
187
        } else {
188
            if($this->_user_total < 0) {
189
                $allUserTotal = 0;
190
            } else {
191
                $allUserTotal = $this->_auth->getUserCount();
192
            }
193
            ptln("<p>".sprintf($this->lang['nonefound'], $allUserTotal)."</p>");
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
194
        }
195
        ptln("<form action=\"".wl($ID)."\" method=\"post\">");
196
        formSecurityToken();
197
        ptln("  <div class=\"table\">");
198
        ptln("  <table class=\"inline\">");
199
        ptln("    <thead>");
200
        ptln("      <tr>");
201
        ptln("        <th>&#160;</th><th>".$this->lang["user_id"]."</th><th>".$this->lang["user_name"]."</th><th>".$this->lang["user_mail"]."</th><th>".$this->lang["user_groups"]."</th>");
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
202
        ptln("      </tr>");
203
204
        ptln("      <tr>");
205
        ptln("        <td class=\"rightalign\"><input type=\"image\" src=\"".DOKU_PLUGIN_IMAGES."search.png\" name=\"fn[search][new]\" title=\"".$this->lang['search_prompt']."\" alt=\"".$this->lang['search']."\" class=\"button\" /></td>");
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
206
        ptln("        <td><input type=\"text\" name=\"userid\" class=\"edit\" value=\"".$this->_htmlFilter('user')."\" /></td>");
207
        ptln("        <td><input type=\"text\" name=\"username\" class=\"edit\" value=\"".$this->_htmlFilter('name')."\" /></td>");
208
        ptln("        <td><input type=\"text\" name=\"usermail\" class=\"edit\" value=\"".$this->_htmlFilter('mail')."\" /></td>");
209
        ptln("        <td><input type=\"text\" name=\"usergroups\" class=\"edit\" value=\"".$this->_htmlFilter('grps')."\" /></td>");
210
        ptln("      </tr>");
211
        ptln("    </thead>");
212
213
        if ($this->_user_total) {
214
            ptln("    <tbody>");
215
            foreach ($user_list as $user => $userinfo) {
216
                extract($userinfo);
217
                /**
218
                 * @var string $name
219
                 * @var string $pass
220
                 * @var string $mail
221
                 * @var array  $grps
222
                 */
223
                $groups = join(', ',$grps);
224
                ptln("    <tr class=\"user_info\">");
225
                ptln("      <td class=\"centeralign\"><input type=\"checkbox\" name=\"delete[".hsc($user)."]\" ".$delete_disable." /></td>");
226
                if ($editable) {
227
                    ptln("    <td><a href=\"".wl($ID,array('fn[edit]['.$user.']' => 1,
228
                                                           'do' => 'admin',
229
                                                           'page' => 'usermanager',
230
                                                           'sectok' => getSecurityToken())).
231
                         "\" title=\"".$this->lang['edit_prompt']."\">".hsc($user)."</a></td>");
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
232
                } else {
233
                    ptln("    <td>".hsc($user)."</td>");
234
                }
235
                ptln("      <td>".hsc($name)."</td><td>".hsc($mail)."</td><td>".hsc($groups)."</td>");
236
                ptln("    </tr>");
237
            }
238
            ptln("    </tbody>");
239
        }
240
241
        ptln("    <tbody>");
242
        ptln("      <tr><td colspan=\"5\" class=\"centeralign\">");
243
        ptln("        <span class=\"medialeft\">");
244
        ptln("          <button type=\"submit\" name=\"fn[delete]\" id=\"usrmgr__del\" ".$delete_disable.">".$this->lang['delete_selected']."</button>");
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
245
        ptln("        </span>");
246
        ptln("        <span class=\"mediaright\">");
247
        ptln("          <button type=\"submit\" name=\"fn[start]\" ".$page_buttons['start'].">".$this->lang['start']."</button>");
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
248
        ptln("          <button type=\"submit\" name=\"fn[prev]\" ".$page_buttons['prev'].">".$this->lang['prev']."</button>");
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
249
        ptln("          <button type=\"submit\" name=\"fn[next]\" ".$page_buttons['next'].">".$this->lang['next']."</button>");
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
250
        ptln("          <button type=\"submit\" name=\"fn[last]\" ".$page_buttons['last'].">".$this->lang['last']."</button>");
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
251
        ptln("        </span>");
252
        if (!empty($this->_filter)) {
253
            ptln("    <button type=\"submit\" name=\"fn[search][clear]\">".$this->lang['clear']."</button>");
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
254
        }
255
        ptln("        <button type=\"submit\" name=\"fn[export]\">".$export_label."</button>");
256
        ptln("        <input type=\"hidden\" name=\"do\"    value=\"admin\" />");
257
        ptln("        <input type=\"hidden\" name=\"page\"  value=\"usermanager\" />");
258
259
        $this->_htmlFilterSettings(2);
260
261
        ptln("      </td></tr>");
262
        ptln("    </tbody>");
263
        ptln("  </table>");
264
        ptln("  </div>");
265
266
        ptln("</form>");
267
        ptln("</div>");
268
269
        $style = $this->_edit_user ? " class=\"edit_user\"" : "";
270
271
        if ($this->_auth->canDo('addUser')) {
272
            ptln("<div".$style.">");
273
            print $this->locale_xhtml('add');
274
            ptln("  <div class=\"level2\">");
275
276
            $this->_htmlUserForm('add',null,array(),4);
277
278
            ptln("  </div>");
279
            ptln("</div>");
280
        }
281
282
        if($this->_edit_user  && $this->_auth->canDo('UserMod')){
283
            ptln("<div".$style." id=\"scroll__here\">");
284
            print $this->locale_xhtml('edit');
285
            ptln("  <div class=\"level2\">");
286
287
            $this->_htmlUserForm('modify',$this->_edit_user,$this->_edit_userdata,4);
288
289
            ptln("  </div>");
290
            ptln("</div>");
291
        }
292
293
        if ($this->_auth->canDo('addUser')) {
294
            $this->_htmlImportForm();
295
        }
296
        ptln("</div>");
297
        return true;
298
    }
299
300
    /**
301
     * Display form to add or modify a user
302
     *
303
     * @param string $cmd 'add' or 'modify'
304
     * @param string $user id of user
305
     * @param array  $userdata array with name, mail, pass and grps
306
     * @param int    $indent
307
     */
308
    protected function _htmlUserForm($cmd,$user='',$userdata=array(),$indent=0) {
309
        global $conf;
310
        global $ID;
311
        global $lang;
312
313
        $name = $mail = $groups = '';
314
        $notes = array();
315
316
        if ($user) {
317
            extract($userdata);
318
            if (!empty($grps)) $groups = join(',',$grps);
319
        } else {
320
            $notes[] = sprintf($this->lang['note_group'],$conf['defaultgroup']);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
321
        }
322
323
        ptln("<form action=\"".wl($ID)."\" method=\"post\">",$indent);
324
        formSecurityToken();
325
        ptln("  <div class=\"table\">",$indent);
326
        ptln("  <table class=\"inline\">",$indent);
327
        ptln("    <thead>",$indent);
328
        ptln("      <tr><th>".$this->lang["field"]."</th><th>".$this->lang["value"]."</th></tr>",$indent);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
329
        ptln("    </thead>",$indent);
330
        ptln("    <tbody>",$indent);
331
332
        $this->_htmlInputField($cmd."_userid",    "userid",    $this->lang["user_id"],    $user,  $this->_auth->canDo("modLogin"),   true, $indent+6);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
333
        $this->_htmlInputField($cmd."_userpass",  "userpass",  $this->lang["user_pass"],  "",     $this->_auth->canDo("modPass"),   false, $indent+6);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
334
        $this->_htmlInputField($cmd."_userpass2", "userpass2", $lang["passchk"],          "",     $this->_auth->canDo("modPass"),   false, $indent+6);
335
        $this->_htmlInputField($cmd."_username",  "username",  $this->lang["user_name"],  $name,  $this->_auth->canDo("modName"),    true, $indent+6);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
336
        $this->_htmlInputField($cmd."_usermail",  "usermail",  $this->lang["user_mail"],  $mail,  $this->_auth->canDo("modMail"),    true, $indent+6);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
337
        $this->_htmlInputField($cmd."_usergroups","usergroups",$this->lang["user_groups"],$groups,$this->_auth->canDo("modGroups"), false, $indent+6);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
338
339
        if ($this->_auth->canDo("modPass")) {
340
            if ($cmd == 'add') {
341
                $notes[] = $this->lang['note_pass'];
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
342
            }
343
            if ($user) {
344
                $notes[] = $this->lang['note_notify'];
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
345
            }
346
347
            ptln("<tr><td><label for=\"".$cmd."_usernotify\" >".$this->lang["user_notify"].": </label></td><td><input type=\"checkbox\" id=\"".$cmd."_usernotify\" name=\"usernotify\" value=\"1\" /></td></tr>", $indent);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
348
        }
349
350
        ptln("    </tbody>",$indent);
351
        ptln("    <tbody>",$indent);
352
        ptln("      <tr>",$indent);
353
        ptln("        <td colspan=\"2\">",$indent);
354
        ptln("          <input type=\"hidden\" name=\"do\"    value=\"admin\" />",$indent);
355
        ptln("          <input type=\"hidden\" name=\"page\"  value=\"usermanager\" />",$indent);
356
357
        // save current $user, we need this to access details if the name is changed
358
        if ($user)
359
          ptln("          <input type=\"hidden\" name=\"userid_old\"  value=\"".hsc($user)."\" />",$indent);
360
361
        $this->_htmlFilterSettings($indent+10);
362
363
        ptln("          <button type=\"submit\" name=\"fn[".$cmd."]\">".$this->lang[$cmd]."</button>",$indent);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
364
        ptln("        </td>",$indent);
365
        ptln("      </tr>",$indent);
366
        ptln("    </tbody>",$indent);
367
        ptln("  </table>",$indent);
368
369
        if ($notes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $notes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
370
            ptln("    <ul class=\"notes\">");
371
            foreach ($notes as $note) {
372
                ptln("      <li><span class=\"li\">".$note."</li>",$indent);
373
            }
374
            ptln("    </ul>");
375
        }
376
        ptln("  </div>",$indent);
377
        ptln("</form>",$indent);
378
    }
379
380
    /**
381
     * Prints a inputfield
382
     *
383
     * @param string $id
384
     * @param string $name
385
     * @param string $label
386
     * @param string $value
387
     * @param bool   $cando whether auth backend is capable to do this action
388
     * @param bool   $required is this field required?
389
     * @param int $indent
390
     */
391
    protected function _htmlInputField($id, $name, $label, $value, $cando, $required, $indent=0) {
392
        $class = $cando ? '' : ' class="disabled"';
393
        echo str_pad('',$indent);
394
395
        if($name == 'userpass' || $name == 'userpass2'){
396
            $fieldtype = 'password';
397
            $autocomp  = 'autocomplete="off"';
398
        }elseif($name == 'usermail'){
399
            $fieldtype = 'email';
400
            $autocomp  = '';
401
        }else{
402
            $fieldtype = 'text';
403
            $autocomp  = '';
404
        }
405
        $value = hsc($value);
406
407
        echo "<tr $class>";
408
        echo "<td><label for=\"$id\" >$label: </label></td>";
409
        echo "<td>";
410
        if($cando){
411
            $req = '';
412
            if($required) $req = 'required="required"';
413
            echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\" value=\"$value\" class=\"edit\" $autocomp $req />";
414
        }else{
415
            echo "<input type=\"hidden\" name=\"$name\" value=\"$value\" />";
416
            echo "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\" value=\"$value\" class=\"edit disabled\" disabled=\"disabled\" />";
417
        }
418
        echo "</td>";
419
        echo "</tr>";
420
    }
421
422
    /**
423
     * Returns htmlescaped filter value
424
     *
425
     * @param string $key name of search field
426
     * @return string html escaped value
427
     */
428
    protected function _htmlFilter($key) {
429
        if (empty($this->_filter)) return '';
430
        return (isset($this->_filter[$key]) ? hsc($this->_filter[$key]) : '');
431
    }
432
433
    /**
434
     * Print hidden inputs with the current filter values
435
     *
436
     * @param int $indent
437
     */
438
    protected function _htmlFilterSettings($indent=0) {
439
440
        ptln("<input type=\"hidden\" name=\"start\" value=\"".$this->_start."\" />",$indent);
441
442
        foreach ($this->_filter as $key => $filter) {
443
            ptln("<input type=\"hidden\" name=\"filter[".$key."]\" value=\"".hsc($filter)."\" />",$indent);
444
        }
445
    }
446
447
    /**
448
     * Print import form and summary of previous import
449
     *
450
     * @param int $indent
451
     */
452
    protected function _htmlImportForm($indent=0) {
453
        global $ID;
454
455
        $failure_download_link = wl($ID,array('do'=>'admin','page'=>'usermanager','fn[importfails]'=>1));
456
457
        ptln('<div class="level2 import_users">',$indent);
458
        print $this->locale_xhtml('import');
459
        ptln('  <form action="'.wl($ID).'" method="post" enctype="multipart/form-data">',$indent);
460
        formSecurityToken();
461
        ptln('    <label>'.$this->lang['import_userlistcsv'].'<input type="file" name="import" /></label>',$indent);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
462
        ptln('    <button type="submit" name="fn[import]">'.$this->lang['import'].'</button>',$indent);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
463
        ptln('    <input type="hidden" name="do"    value="admin" />',$indent);
464
        ptln('    <input type="hidden" name="page"  value="usermanager" />',$indent);
465
466
        $this->_htmlFilterSettings($indent+4);
467
        ptln('  </form>',$indent);
468
        ptln('</div>');
469
470
        // list failures from the previous import
471
        if ($this->_import_failures) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_import_failures of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
472
            $digits = strlen(count($this->_import_failures));
473
            ptln('<div class="level3 import_failures">',$indent);
474
            ptln('  <h3>'.$this->lang['import_header'].'</h3>');
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
475
            ptln('  <table class="import_failures">',$indent);
476
            ptln('    <thead>',$indent);
477
            ptln('      <tr>',$indent);
478
            ptln('        <th class="line">'.$this->lang['line'].'</th>',$indent);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
479
            ptln('        <th class="error">'.$this->lang['error'].'</th>',$indent);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
480
            ptln('        <th class="userid">'.$this->lang['user_id'].'</th>',$indent);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
481
            ptln('        <th class="username">'.$this->lang['user_name'].'</th>',$indent);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
482
            ptln('        <th class="usermail">'.$this->lang['user_mail'].'</th>',$indent);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
483
            ptln('        <th class="usergroups">'.$this->lang['user_groups'].'</th>',$indent);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
484
            ptln('      </tr>',$indent);
485
            ptln('    </thead>',$indent);
486
            ptln('    <tbody>',$indent);
487
            foreach ($this->_import_failures as $line => $failure) {
488
                ptln('      <tr>',$indent);
489
                ptln('        <td class="lineno"> '.sprintf('%0'.$digits.'d',$line).' </td>',$indent);
490
                ptln('        <td class="error">' .$failure['error'].' </td>', $indent);
491
                ptln('        <td class="field userid"> '.hsc($failure['user'][0]).' </td>',$indent);
492
                ptln('        <td class="field username"> '.hsc($failure['user'][2]).' </td>',$indent);
493
                ptln('        <td class="field usermail"> '.hsc($failure['user'][3]).' </td>',$indent);
494
                ptln('        <td class="field usergroups"> '.hsc($failure['user'][4]).' </td>',$indent);
495
                ptln('      </tr>',$indent);
496
            }
497
            ptln('    </tbody>',$indent);
498
            ptln('  </table>',$indent);
499
            ptln('  <p><a href="'.$failure_download_link.'">'.$this->lang['import_downloadfailures'].'</a></p>');
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
500
            ptln('</div>');
501
        }
502
503
    }
504
505
    /**
506
     * Add an user to auth backend
507
     *
508
     * @return bool whether succesful
509
     */
510
    protected function _addUser(){
511
        global $INPUT;
512
        if (!checkSecurityToken()) return false;
513
        if (!$this->_auth->canDo('addUser')) return false;
514
515
        list($user,$pass,$name,$mail,$grps,$passconfirm) = $this->_retrieveUser();
516
        if (empty($user)) return false;
517
518
        if ($this->_auth->canDo('modPass')){
519
            if (empty($pass)){
520
                if($INPUT->has('usernotify')){
521
                    $pass = auth_pwgen($user);
522
                } else {
523
                    msg($this->lang['add_fail'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
524
                    msg($this->lang['addUser_error_missing_pass'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
525
                    return false;
526
                }
527
            } else {
528
                if (!$this->_verifyPassword($pass,$passconfirm)) {
529
                    msg($this->lang['add_fail'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
530
                    msg($this->lang['addUser_error_pass_not_identical'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
531
                    return false;
532
                }
533
            }
534
        } else {
535
            if (!empty($pass)){
536
                msg($this->lang['add_fail'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
537
                msg($this->lang['addUser_error_modPass_disabled'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
538
                return false;
539
            }
540
        }
541
542
        if ($this->_auth->canDo('modName')){
543
            if (empty($name)){
544
                msg($this->lang['add_fail'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
545
                msg($this->lang['addUser_error_name_missing'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
546
                return false;
547
            }
548
        } else {
549
            if (!empty($name)){
550
                msg($this->lang['add_fail'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
551
                msg($this->lang['addUser_error_modName_disabled'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
552
                return false;
553
            }
554
        }
555
556
        if ($this->_auth->canDo('modMail')){
557
            if (empty($mail)){
558
                msg($this->lang['add_fail'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
559
                msg($this->lang['addUser_error_mail_missing'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
560
                return false;
561
            }
562
        } else {
563
            if (!empty($mail)){
564
                msg($this->lang['add_fail'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
565
                msg($this->lang['addUser_error_modMail_disabled'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
566
                return false;
567
            }
568
        }
569
570
        if ($ok = $this->_auth->triggerUserMod('create', array($user,$pass,$name,$mail,$grps))) {
571
572
            msg($this->lang['add_ok'], 1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
573
574
            if ($INPUT->has('usernotify') && $pass) {
575
                $this->_notifyUser($user,$pass);
576
            }
577
        } else {
578
            msg($this->lang['add_fail'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
579
            msg($this->lang['addUser_error_create_event_failed'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
580
        }
581
582
        return $ok;
583
    }
584
585
    /**
586
     * Delete user from auth backend
587
     *
588
     * @return bool whether succesful
589
     */
590
    protected function _deleteUser(){
591
        global $conf, $INPUT;
592
593
        if (!checkSecurityToken()) return false;
594
        if (!$this->_auth->canDo('delUser')) return false;
595
596
        $selected = $INPUT->arr('delete');
597
        if (empty($selected)) return false;
598
        $selected = array_keys($selected);
599
600
        if(in_array($_SERVER['REMOTE_USER'], $selected)) {
601
            msg("You can't delete yourself!", -1);
602
            return false;
603
        }
604
605
        $count = $this->_auth->triggerUserMod('delete', array($selected));
606
        if ($count == count($selected)) {
607
            $text = str_replace('%d', $count, $this->lang['delete_ok']);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
608
            msg("$text.", 1);
609
        } else {
610
            $part1 = str_replace('%d', $count, $this->lang['delete_ok']);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
611
            $part2 = str_replace('%d', (count($selected)-$count), $this->lang['delete_fail']);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
612
            msg("$part1, $part2",-1);
613
        }
614
615
        // invalidate all sessions
616
        io_saveFile($conf['cachedir'].'/sessionpurge',time());
617
618
        return true;
619
    }
620
621
    /**
622
     * Edit user (a user has been selected for editing)
623
     *
624
     * @param string $param id of the user
625
     * @return bool whether succesful
626
     */
627
    protected function _editUser($param) {
628
        if (!checkSecurityToken()) return false;
629
        if (!$this->_auth->canDo('UserMod')) return false;
630
        $user = $this->_auth->cleanUser(preg_replace('/.*[:\/]/','',$param));
631
        $userdata = $this->_auth->getUserData($user);
632
633
        // no user found?
634
        if (!$userdata) {
635
            msg($this->lang['edit_usermissing'],-1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
636
            return false;
637
        }
638
639
        $this->_edit_user = $user;
640
        $this->_edit_userdata = $userdata;
0 ignored issues
show
Documentation Bug introduced by
It seems like $userdata of type boolean is incompatible with the declared type array of property $_edit_userdata.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
641
642
        return true;
643
    }
644
645
    /**
646
     * Modify user in the auth backend (modified user data has been recieved)
647
     *
648
     * @return bool whether succesful
649
     */
650
    protected function _modifyUser(){
651
        global $conf, $INPUT;
652
653
        if (!checkSecurityToken()) return false;
654
        if (!$this->_auth->canDo('UserMod')) return false;
655
656
        // get currently valid  user data
657
        $olduser = $this->_auth->cleanUser(preg_replace('/.*[:\/]/','',$INPUT->str('userid_old')));
658
        $oldinfo = $this->_auth->getUserData($olduser);
659
660
        // get new user data subject to change
661
        list($newuser,$newpass,$newname,$newmail,$newgrps,$passconfirm) = $this->_retrieveUser();
662
        if (empty($newuser)) return false;
663
664
        $changes = array();
665
        if ($newuser != $olduser) {
666
667
            if (!$this->_auth->canDo('modLogin')) {        // sanity check, shouldn't be possible
668
                msg($this->lang['update_fail'],-1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
669
                return false;
670
            }
671
672
            // check if $newuser already exists
673
            if ($this->_auth->getUserData($newuser)) {
674
                msg(sprintf($this->lang['update_exists'],$newuser),-1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
675
                $re_edit = true;
676
            } else {
677
                $changes['user'] = $newuser;
678
            }
679
        }
680
        if ($this->_auth->canDo('modPass')) {
681
            if ($newpass || $passconfirm) {
682
                if ($this->_verifyPassword($newpass,$passconfirm)) {
683
                    $changes['pass'] = $newpass;
684
                } else {
685
                    return false;
686
                }
687
            } else {
688
                // no new password supplied, check if we need to generate one (or it stays unchanged)
689
                if ($INPUT->has('usernotify')) {
690
                    $changes['pass'] = auth_pwgen($olduser);
691
                }
692
            }
693
        }
694
695
        if (!empty($newname) && $this->_auth->canDo('modName') && $newname != $oldinfo['name']) {
696
            $changes['name'] = $newname;
697
        }
698
        if (!empty($newmail) && $this->_auth->canDo('modMail') && $newmail != $oldinfo['mail']) {
699
            $changes['mail'] = $newmail;
700
        }
701
        if (!empty($newgrps) && $this->_auth->canDo('modGroups') && $newgrps != $oldinfo['grps']) {
702
            $changes['grps'] = $newgrps;
703
        }
704
705
        if ($ok = $this->_auth->triggerUserMod('modify', array($olduser, $changes))) {
706
            msg($this->lang['update_ok'],1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
707
708
            if ($INPUT->has('usernotify') && !empty($changes['pass'])) {
709
                $notify = empty($changes['user']) ? $olduser : $newuser;
710
                $this->_notifyUser($notify,$changes['pass']);
711
            }
712
713
            // invalidate all sessions
714
            io_saveFile($conf['cachedir'].'/sessionpurge',time());
715
716
        } else {
717
            msg($this->lang['update_fail'],-1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
718
        }
719
720
        if (!empty($re_edit)) {
721
            $this->_editUser($olduser);
722
        }
723
724
        return $ok;
725
    }
726
727
    /**
728
     * Send password change notification email
729
     *
730
     * @param string $user         id of user
731
     * @param string $password     plain text
732
     * @param bool   $status_alert whether status alert should be shown
733
     * @return bool whether succesful
734
     */
735
    protected function _notifyUser($user, $password, $status_alert=true) {
736
737
        if ($sent = auth_sendPassword($user,$password)) {
738
            if ($status_alert) {
739
                msg($this->lang['notify_ok'], 1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
740
            }
741
        } else {
742
            if ($status_alert) {
743
                msg($this->lang['notify_fail'], -1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
744
            }
745
        }
746
747
        return $sent;
748
    }
749
750
    /**
751
     * Verify password meets minimum requirements
752
     * :TODO: extend to support password strength
753
     *
754
     * @param string  $password   candidate string for new password
755
     * @param string  $confirm    repeated password for confirmation
756
     * @return bool   true if meets requirements, false otherwise
757
     */
758
    protected function _verifyPassword($password, $confirm) {
759
        global $lang;
760
761
        if (empty($password) && empty($confirm)) {
762
            return false;
763
        }
764
765
        if ($password !== $confirm) {
766
            msg($lang['regbadpass'], -1);
767
            return false;
768
        }
769
770
        // :TODO: test password for required strength
771
772
        // if we make it this far the password is good
773
        return true;
774
    }
775
776
    /**
777
     * Retrieve & clean user data from the form
778
     *
779
     * @param bool $clean whether the cleanUser method of the authentication backend is applied
780
     * @return array (user, password, full name, email, array(groups))
781
     */
782
    protected function _retrieveUser($clean=true) {
783
        /** @var DokuWiki_Auth_Plugin $auth */
784
        global $auth;
785
        global $INPUT;
786
787
        $user = array();
788
        $user[0] = ($clean) ? $auth->cleanUser($INPUT->str('userid')) : $INPUT->str('userid');
789
        $user[1] = $INPUT->str('userpass');
790
        $user[2] = $INPUT->str('username');
791
        $user[3] = $INPUT->str('usermail');
792
        $user[4] = explode(',',$INPUT->str('usergroups'));
793
        $user[5] = $INPUT->str('userpass2');                // repeated password for confirmation
794
795
        $user[4] = array_map('trim',$user[4]);
796
        if($clean) $user[4] = array_map(array($auth,'cleanGroup'),$user[4]);
797
        $user[4] = array_filter($user[4]);
798
        $user[4] = array_unique($user[4]);
799
        if(!count($user[4])) $user[4] = null;
800
801
        return $user;
802
    }
803
804
    /**
805
     * Set the filter with the current search terms or clear the filter
806
     *
807
     * @param string $op 'new' or 'clear'
808
     */
809
    protected function _setFilter($op) {
810
811
        $this->_filter = array();
812
813
        if ($op == 'new') {
814
            list($user,/* $pass */,$name,$mail,$grps) = $this->_retrieveUser(false);
815
816
            if (!empty($user)) $this->_filter['user'] = $user;
817
            if (!empty($name)) $this->_filter['name'] = $name;
818
            if (!empty($mail)) $this->_filter['mail'] = $mail;
819
            if (!empty($grps)) $this->_filter['grps'] = join('|',$grps);
820
        }
821
    }
822
823
    /**
824
     * Get the current search terms
825
     *
826
     * @return array
827
     */
828
    protected function _retrieveFilter() {
829
        global $INPUT;
830
831
        $t_filter = $INPUT->arr('filter');
832
833
        // messy, but this way we ensure we aren't getting any additional crap from malicious users
834
        $filter = array();
835
836
        if (isset($t_filter['user'])) $filter['user'] = $t_filter['user'];
837
        if (isset($t_filter['name'])) $filter['name'] = $t_filter['name'];
838
        if (isset($t_filter['mail'])) $filter['mail'] = $t_filter['mail'];
839
        if (isset($t_filter['grps'])) $filter['grps'] = $t_filter['grps'];
840
841
        return $filter;
842
    }
843
844
    /**
845
     * Validate and improve the pagination values
846
     */
847
    protected function _validatePagination() {
848
849
        if ($this->_start >= $this->_user_total) {
850
            $this->_start = $this->_user_total - $this->_pagesize;
851
        }
852
        if ($this->_start < 0) $this->_start = 0;
853
854
        $this->_last = min($this->_user_total, $this->_start + $this->_pagesize);
855
    }
856
857
    /**
858
     * Return an array of strings to enable/disable pagination buttons
859
     *
860
     * @return array with enable/disable attributes
861
     */
862
    protected function _pagination() {
863
864
        $disabled = 'disabled="disabled"';
865
866
        $buttons = array();
867
        $buttons['start'] = $buttons['prev'] = ($this->_start == 0) ? $disabled : '';
868
869
        if ($this->_user_total == -1) {
870
            $buttons['last'] = $disabled;
871
            $buttons['next'] = '';
872
        } else {
873
            $buttons['last'] = $buttons['next'] = (($this->_start + $this->_pagesize) >= $this->_user_total) ? $disabled : '';
874
        }
875
876
        if ($this->_lastdisabled) {
877
            $buttons['last'] = $disabled;
878
        }
879
880
        return $buttons;
881
    }
882
883
    /**
884
     * Export a list of users in csv format using the current filter criteria
885
     */
886
    protected function _export() {
887
        // list of users for export - based on current filter criteria
888
        $user_list = $this->_auth->retrieveUsers(0, 0, $this->_filter);
889
        $column_headings = array(
890
            $this->lang["user_id"],
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
891
            $this->lang["user_name"],
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
892
            $this->lang["user_mail"],
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
893
            $this->lang["user_groups"]
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
894
        );
895
896
        // ==============================================================================================
897
        // GENERATE OUTPUT
898
        // normal headers for downloading...
899
        header('Content-type: text/csv;charset=utf-8');
900
        header('Content-Disposition: attachment; filename="wikiusers.csv"');
901
#       // for debugging assistance, send as text plain to the browser
902
#       header('Content-type: text/plain;charset=utf-8');
903
904
        // output the csv
905
        $fd = fopen('php://output','w');
906
        fputcsv($fd, $column_headings);
907
        foreach ($user_list as $user => $info) {
908
            $line = array($user, $info['name'], $info['mail'], join(',',$info['grps']));
909
            fputcsv($fd, $line);
910
        }
911
        fclose($fd);
912
        if (defined('DOKU_UNITTEST')){ return; }
913
914
        die;
915
    }
916
917
    /**
918
     * Import a file of users in csv format
919
     *
920
     * csv file should have 4 columns, user_id, full name, email, groups (comma separated)
921
     *
922
     * @return bool whether successful
923
     */
924
    protected function _import() {
925
        // check we are allowed to add users
926
        if (!checkSecurityToken()) return false;
927
        if (!$this->_auth->canDo('addUser')) return false;
928
929
        // check file uploaded ok.
930
        if (empty($_FILES['import']['size']) || !empty($_FILES['import']['error']) && $this->_isUploadedFile($_FILES['import']['tmp_name'])) {
931
            msg($this->lang['import_error_upload'],-1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
932
            return false;
933
        }
934
        // retrieve users from the file
935
        $this->_import_failures = array();
936
        $import_success_count = 0;
937
        $import_fail_count = 0;
938
        $line = 0;
939
        $fd = fopen($_FILES['import']['tmp_name'],'r');
940
        if ($fd) {
941
            while($csv = fgets($fd)){
942
                if (!utf8_check($csv)) {
943
                    $csv = utf8_encode($csv);
944
                }
945
                $raw = $this->_getcsv($csv);
0 ignored issues
show
Deprecated Code introduced by
The method admin_plugin_usermanager::_getcsv() has been deprecated with message: remove when dokuwiki php requirement increases to 5.3+ also associated unit test & mock access method

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
946
                $error = '';                        // clean out any errors from the previous line
947
                // data checks...
948
                if (1 == ++$line) {
949
                    if ($raw[0] == 'user_id' || $raw[0] == $this->lang['user_id']) continue;    // skip headers
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
950
                }
951
                if (count($raw) < 4) {                                        // need at least four fields
952
                    $import_fail_count++;
953
                    $error = sprintf($this->lang['import_error_fields'], count($raw));
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
954
                    $this->_import_failures[$line] = array('error' => $error, 'user' => $raw, 'orig' => $csv);
955
                    continue;
956
                }
957
                array_splice($raw,1,0,auth_pwgen());                          // splice in a generated password
958
                $clean = $this->_cleanImportUser($raw, $error);
959
                if ($clean && $this->_addImportUser($clean, $error)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $clean of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
960
                    $sent = $this->_notifyUser($clean[0],$clean[1],false);
961
                    if (!$sent){
962
                        msg(sprintf($this->lang['import_notify_fail'],$clean[0],$clean[3]),-1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
963
                    }
964
                    $import_success_count++;
965
                } else {
966
                    $import_fail_count++;
967
                    array_splice($raw, 1, 1);                                  // remove the spliced in password
968
                    $this->_import_failures[$line] = array('error' => $error, 'user' => $raw, 'orig' => $csv);
969
                }
970
            }
971
            msg(sprintf($this->lang['import_success_count'], ($import_success_count+$import_fail_count), $import_success_count),($import_success_count ? 1 : -1));
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
972
            if ($import_fail_count) {
973
                msg(sprintf($this->lang['import_failure_count'], $import_fail_count),-1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
974
            }
975
        } else {
976
            msg($this->lang['import_error_readfail'],-1);
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
977
        }
978
979
        // save import failures into the session
980
        if (!headers_sent()) {
981
            session_start();
982
            $_SESSION['import_failures'] = $this->_import_failures;
983
            session_write_close();
984
        }
985
        return true;
986
    }
987
988
    /**
989
     * Returns cleaned user data
990
     *
991
     * @param array $candidate raw values of line from input file
992
     * @param string $error
993
     * @return array|false cleaned data or false
994
     */
995
    protected function _cleanImportUser($candidate, & $error){
996
        global $INPUT;
997
998
        // kludgy ....
999
        $INPUT->set('userid', $candidate[0]);
1000
        $INPUT->set('userpass', $candidate[1]);
1001
        $INPUT->set('username', $candidate[2]);
1002
        $INPUT->set('usermail', $candidate[3]);
1003
        $INPUT->set('usergroups', $candidate[4]);
1004
1005
        $cleaned = $this->_retrieveUser();
1006
        list($user,/* $pass */,$name,$mail,/* $grps */) = $cleaned;
1007
        if (empty($user)) {
1008
            $error = $this->lang['import_error_baduserid'];
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1009
            return false;
1010
        }
1011
1012
        // no need to check password, handled elsewhere
1013
1014
        if (!($this->_auth->canDo('modName') xor empty($name))){
1015
            $error = $this->lang['import_error_badname'];
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1016
            return false;
1017
        }
1018
1019
        if ($this->_auth->canDo('modMail')) {
1020
            if (empty($mail) || !mail_isvalid($mail)) {
1021
                $error = $this->lang['import_error_badmail'];
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1022
                return false;
1023
            }
1024
        } else {
1025
            if (!empty($mail)) {
1026
                $error = $this->lang['import_error_badmail'];
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1027
                return false;
1028
            }
1029
        }
1030
1031
        return $cleaned;
1032
    }
1033
1034
    /**
1035
     * Adds imported user to auth backend
1036
     *
1037
     * Required a check of canDo('addUser') before
1038
     *
1039
     * @param array  $user   data of user
1040
     * @param string &$error reference catched error message
1041
     * @return bool whether successful
1042
     */
1043
    protected function _addImportUser($user, & $error){
1044
        if (!$this->_auth->triggerUserMod('create', $user)) {
1045
            $error = $this->lang['import_error_create'];
0 ignored issues
show
Bug introduced by
The property lang cannot be accessed from this context as it is declared private in class DokuWiki_Plugin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
1046
            return false;
1047
        }
1048
1049
        return true;
1050
    }
1051
1052
    /**
1053
     * Downloads failures as csv file
1054
     */
1055
    protected function _downloadImportFailures(){
1056
1057
        // ==============================================================================================
1058
        // GENERATE OUTPUT
1059
        // normal headers for downloading...
1060
        header('Content-type: text/csv;charset=utf-8');
1061
        header('Content-Disposition: attachment; filename="importfails.csv"');
1062
#       // for debugging assistance, send as text plain to the browser
1063
#       header('Content-type: text/plain;charset=utf-8');
1064
1065
        // output the csv
1066
        $fd = fopen('php://output','w');
1067
        foreach ($this->_import_failures as $fail) {
1068
            fputs($fd, $fail['orig']);
1069
        }
1070
        fclose($fd);
1071
        die;
1072
    }
1073
1074
    /**
1075
     * wrapper for is_uploaded_file to facilitate overriding by test suite
1076
     *
1077
     * @param string $file filename
1078
     * @return bool
1079
     */
1080
    protected function _isUploadedFile($file) {
1081
        return is_uploaded_file($file);
1082
    }
1083
1084
    /**
1085
     * wrapper for str_getcsv() to simplify maintaining compatibility with php 5.2
1086
     *
1087
     * @deprecated    remove when dokuwiki php requirement increases to 5.3+
1088
     *                also associated unit test & mock access method
1089
     *
1090
     * @param string $csv string to parse
1091
     * @return array
1092
     */
1093
    protected function _getcsv($csv) {
1094
        return function_exists('str_getcsv') ? str_getcsv($csv) : $this->str_getcsv($csv);
0 ignored issues
show
Deprecated Code introduced by
The method admin_plugin_usermanager::str_getcsv() has been deprecated with message: remove when dokuwiki php requirement increases to 5.3+

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1095
    }
1096
1097
    /**
1098
     * replacement str_getcsv() function for php < 5.3
1099
     * loosely based on www.php.net/str_getcsv#88311
1100
     *
1101
     * @deprecated    remove when dokuwiki php requirement increases to 5.3+
1102
     *
1103
     * @param string $str string to parse
1104
     * @return array
1105
     */
1106
    protected function str_getcsv($str) {
1107
        $fp = fopen("php://temp/maxmemory:1048576", 'r+');    // 1MiB
1108
        fputs($fp, $str);
1109
        rewind($fp);
1110
1111
        $data = fgetcsv($fp);
1112
1113
        fclose($fp);
1114
        return $data;
1115
    }
1116
}
1117