Completed
Pull Request — remoteapiGetversions (#1573)
by Gerrit
06:07 queued 01:35
created

admin_plugin_usermanager::_notifyUser()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 14
rs 9.2
cc 4
eloc 8
nc 4
nop 3
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 = str_getcsv($csv);
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