1<?php
2/**
3 * registers users by means of a confirmation link
4 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
5 * @author     Myron Turner<turnermm02@shaw.ca>
6 */
7
8// must be run within Dokuwiki
9if(!defined('DOKU_INC')) die();
10
11if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
12require_once(DOKU_PLUGIN.'action.php');
13require_once(DOKU_INC. 'inc/auth.php');
14
15class action_plugin_preregister extends DokuWiki_Action_Plugin {
16
17    /**
18     * register the eventhandlers
19     */
20    private $metaFn;
21    private $captcha;
22
23    function register(Doku_Event_Handler $controller){
24            $controller->register_hook('FORM_REGISTER_OUTPUT', 'BEFORE', $this, 'update_register_form');
25            $controller->register_hook('HTML_REGISTERFORM_OUTPUT', 'BEFORE', $this, 'update_register_form');
26            $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE',  $this, 'allow_preregister_check');
27            $controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE',  $this, 'process_preregister_check');
28            $controller->register_hook('TPL_METAHEADER_OUTPUT', 'AFTER', $this, 'metaheaders_after');
29     }
30
31    function __construct() {
32       $metafile= 'preregister:db';
33       $this->metaFn = metaFN($metafile,'.ser');
34       $this->check_captcha_selection();
35    }
36    function metaheaders_after (&$event, $param) {
37         global $ACT;
38         if($ACT !== 'register') return;
39
40         if($this->captcha == 'none' || $this->captcha == 'builtin')  {
41            ptln( "\n<style type='text/css'>\n   /*<![CDATA[*/");
42            ptln("#plugin__captcha_wrapper{ display:none; }\n   /*]]>*/\n</style>");
43         }
44
45    }
46
47
48   function allow_preregister_check(&$event, $param) {
49    $act = $this->_act_clean($event->data);
50    if($act != 'preregistercheck') return;
51    $event->preventDefault();
52  }
53
54    function process_preregister_check(&$event, $param) {
55         global $ACT, $INPUT;
56
57         if($ACT != 'preregistercheck') return;
58         if($_GET && $_GET['prereg']) {
59             $md5= $INPUT->str('prereg');
60             if(!preg_match("/^(\w){32}$/",$md5,$matches)) return;;
61             echo $this->getLang('registering') . $md5;
62             $this->process_registration($md5);
63             $event->preventDefault();
64             return;
65         }
66
67        $event->preventDefault();
68
69          if(!$_POST['login']){
70            msg('missing login: please fill out all fields');
71            return;
72          }
73          else if(!$_POST['fullname']) {
74             msg('missing Real Name: please fill out all fields');
75            return;
76          }
77
78        if($this->captcha =='captcha') {
79            $captcha = $this->loadHelper('captcha', true);
80            if(!$captcha->check()) {
81               return;
82            }
83        }
84
85         if($this->is_user($_REQUEST['login']))  return;  // name already taken
86         if($this->captcha == 'builtin') {
87             $failed = false;
88             if(!isset($_REQUEST['card'])) {
89               echo '<h4>'. $this->getLang('cards_nomatch') . '</h4>';
90               return;
91             }
92             foreach($_REQUEST['card'] as $card) {
93                 if(strpos($_REQUEST['sel'],$card) === false) {
94                     $failed = true;
95                     break;
96                 }
97              }
98             if($failed) {
99                 echo '<h4>'. $this->getLang('cards_nomatch') . '</h4>';
100                 return;
101            }
102        }
103        $t = time();
104        $salt =  auth_cookiesalt();
105        $index = md5(microtime() .  $salt);
106        $url = DOKU_URL . 'doku.php?' . htmlentities($INPUT->str('id')). '&do=preregistercheck&prereg='. $index;
107        if($this->getConf('send_confirm')) {
108            $valid_email = true;
109            if($this->send_link($_REQUEST['email'], $url,$valid_email) ) {
110              echo $this->getLang('confirmation');
111            }
112            else if($valid_email) {
113                echo $this->getLang('email_problem');
114            }
115        }
116        else {
117           echo "<a href='$url'>$url</a><br /><br />\n";
118           echo $this->getLang('screen_confirm');
119        }
120
121          $data = unserialize(io_readFile($this->metaFn,false));
122          if(!$data) $data = array();
123          $data[$index] = $_POST;
124          $data[$index]['savetime'] = $t;
125          io_saveFile($this->metaFn,serialize($data));
126    }
127
128    function update_register_form(&$event, $param) {
129        if($_SERVER['REMOTE_USER']){
130            return;
131        }
132        $form = $event->data;
133        $form_update = false;
134        if(is_a($form,\dokuwiki\Form\Form::class)) {
135            $form_update = true;
136            $form->setHiddenField('save', 0);
137            $form->setHiddenField('do', 'preregistercheck');
138        }
139        else {
140        $event->data->_hidden['save'] = 0;
141        $event->data->_hidden['do'] = 'preregistercheck';
142        }
143        if(!$form_update) {
144        for($i=0; $i <count($event->data->_content); $i++) {
145            if(isset($event->data->_content[$i]['type']) && $event->data->_content[$i]['type'] == 'submit')
146            {
147                $event->data->_content[$i]['value'] = 'Submit';
148                break;
149            }
150        }
151        }
152
153        else {
154            $pos = $form->findPositionByAttribute('type','submit');
155            $form->removeElement($pos);
156            $button = $form->addButton('preregister','submit');
157            $button->attrs(['type' => 'submit','value'=>'Submit']);
158        }
159
160        if($form_update) {
161            $pos = $form->findPositionByAttribute('type','submit');
162        }
163        else $pos = $event->data->findElementByAttribute('type','submit');
164        if(!$pos) return; // no button -> source view mode
165        if($this->captcha == 'builtin') {
166            $cards = $this-> get_cards();
167            $sel ="";
168            $out = $this->format_cards($cards,$sel);
169            if($form_update) {
170                  $form->setHiddenField('sel',implode("",$sel));
171                  $form->addHTML($out,$pos++);
172            }
173            else {
174            $event->data->_hidden['sel'] = implode("",$sel);
175           $event->data->insertElement($pos++,$out);
176        }
177    }
178    }
179
180
181    function process_registration($index) {
182
183           $data = unserialize(io_readFile($this->metaFn,false));
184           if(!isset($data[$index])) {
185              msg($this->getLang('old_confirmation'));
186              return;
187           }
188           $post = $data[$index];
189           $post['save'] = 1;
190           $_POST= array_merge($post, array());
191           if(register()) {
192              unset($data[$index]);
193              io_saveFile($this->metaFn,serialize($data));
194           }
195
196    }
197
198
199    function check_captcha_selection() {
200       $list = plugin_list();
201       $this->captcha = $this->getConf('captcha');
202       if(!in_array('captcha', $list)) {
203           if(preg_match("/captcha/", $this->captcha)) {
204               $this->captcha = 'builtin';
205           }
206           return;
207       }
208       if($this->captcha == 'none' || $this->captcha == 'builtin')  {
209           return;
210       }
211      if(plugin_isdisabled('captcha')) {
212          $this->captcha = 'builtin';
213          return;
214      }
215      $this->captcha ='captcha';
216
217    }
218
219    /**
220     * Pre-Sanitize the action command
221     *
222     * Similar to act_clean in action.php but simplified and without
223     * error messages
224     */
225    function _act_clean($act){
226         // check if the action was given as array key
227         if(is_array($act)){
228           list($act) = array_keys($act);
229         }
230
231         //remove all bad chars
232         $act = strtolower($act);
233         $act = preg_replace('/[^a-z_]+/','',$act);
234
235         return $act;
236     }
237
238    function format_cards($cards,&$sel) {
239        $sel = array_slice($cards,0,3);
240        shuffle($cards);
241        $new_row = (int)(count($cards)/2);
242        $out = $sel[0] . '&nbsp;&nbsp;' . $sel[1] . '&nbsp;&nbsp;' . $sel[2] . '<br />';
243        $out = str_replace(array('H','S','D','C'),array('&#9829;','&#9824;','&#9830;','&#9827;'),$out);
244        $out = $this->getLang('check_matching'). '<br />' . $out;
245        $out .= '<center><table cellspacing="2"><tr>';
246        $i=0;
247        foreach($cards as $card) {
248            $i++;
249            $name = 'card[]';
250
251            $out .= '<td>' . str_replace(array('H','S','D','C'),array('&#9829;','&#9824;','&#9830;','&#9827;'),$card)
252                    . " <input type = 'checkbox' name = '$name' value = '$card' /></td>";
253            if($i==$new_row) $out .='</tr><tr>';
254        }
255        $out .= '</tr></table></center>';
256        return $out;
257   }
258
259    function get_cards() {
260         for($i=1; $i<14; $i++) {
261            $c = $i;
262            if($i == 1) {
263              $c='A';
264             }
265            if($i == 11) {
266              $c='J';
267            }
268             if($c == 12) {
269              $c='Q';
270            }
271            if($i == 13) {
272              $c='K';
273            }
274            $hearts[] = $c . "H";
275            $clubs[] = $c. "C";
276            $diamonds[] = $c ."D";
277            $spades[] =  $c."S";
278         }
279     $deck = array_merge($hearts,$clubs, $diamonds, $spades);
280     shuffle($deck);
281      return array_slice($deck,0,10);
282    }
283
284
285    function send_link($email, $url, &$valid_email) {
286
287        if(!mail_isvalid($email)) {
288             msg($this->getLang('bad_email') . $email);
289             $valid_email = false;
290             return false;
291        }
292
293        $text = $this->getLang('email_confirm')  . "\n\n";
294        $text .= "@URL@\n\n";
295        $subject =$this->getLang('subject_confirm');
296
297        $mail = new Mailer();
298        $mail->to($email);
299        $mail->subject($subject);
300        $mail->setBody($text, array('url'=>$url));
301        return $mail->send();
302}
303
304function is_user($uname) {
305    global $config_cascade;
306    $authusers = $config_cascade['plainauth.users']['default'];
307    if(!is_readable($authusers)) return false;
308
309    $users = file($authusers);
310    $uname = utf8_strtolower($uname);
311    foreach($users as $line) {
312        $line = trim($line);
313        if($line{0} == '#') continue;
314        list($user,$rest) = preg_split('/:/',$line,2);
315        if(!trim($user)) continue;
316        if($uname == $user) {
317           msg($this->getLang('uid_inuse') . $user,-1);
318           return true;
319        }
320    }
321    return false;
322 }
323
324    function write_debug($what, $toscreen=true, $tofile=false) {
325
326        if(is_array($what)) {
327            $what = print_r($what,true);
328        }
329        if($toscreen) {
330           return "<pre>$what</pre>" ;
331        }
332        if(!$tofile) {
333           return "";
334        }
335
336
337       $handle=fopen('preregister.txt','a');
338        fwrite($handle, "$what\n");
339        fclose($handle);
340     }
341}
342
343