1<?php
2// must be run within DokuWiki
3if(!defined('DOKU_INC')) die();
4
5if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
6require_once DOKU_PLUGIN.'syntax.php';
7
8/**
9 * Change {{ passwords }} to passwords.
10 * set amount/length using url parameters like passwords?length=3&amount=2.
11 */
12class syntax_plugin_passwords extends DokuWiki_Syntax_Plugin
13{
14    /**
15     * @var string allowed characters
16     */
17    private $allowedCharacters = 'abcdefghjkmnpqrstuvwxyz123456789ABCDEFGHJKLMNPQRSTUVWXYZ';
18
19    /**
20     * @var int amount of passwords
21     */
22    private $amount = 4;
23
24    /**
25     * @var int length of password
26     */
27    private $length = 8;
28
29    /**
30     * @var int iterator
31     */
32    private $iterator = 0;
33
34    /**
35     * get plugin type
36     *
37     * @return string
38     */
39    public function getType() {
40        return 'substition';
41    }
42
43    /**
44     * get sorting order
45     *
46     * @return int
47     */
48    public function getSort() {
49        return 32;
50    }
51
52    /**
53     * Define matching strings
54     *
55     * @param string $mode
56     */
57    public function connectTo($mode) {
58        $this->Lexer->addSpecialPattern('\{\{ passwords }}', $mode, 'plugin_passwords');
59        $this->Lexer->addSpecialPattern('\{\{ passwords\? }}', $mode, 'plugin_passwords');
60        $this->Lexer->addSpecialPattern('\{\{ passwords\?amount=\d*&length=\d* }}', $mode, 'plugin_passwords');
61        $this->Lexer->addSpecialPattern('\{\{ passwords\?length=\d*&amount=\d* }}', $mode, 'plugin_passwords');
62        $this->Lexer->addSpecialPattern('\{\{ passwords\?amount=\d* }}', $mode, 'plugin_passwords');
63        $this->Lexer->addSpecialPattern('\{\{ passwords\?length=\d* }}', $mode, 'plugin_passwords');
64    }
65
66    /**
67     * set the parameters for $data for the render function
68     *
69     * @param string $match gematchte string
70     * @param int $state
71     * @param int $pos
72     * @param DokuHandler $handler
73     *
74     * @return array
75     */
76    public function handle($match, $state, $pos, Doku_Handler $handler) {
77        return array($match, $state, $pos);
78    }
79
80    /**
81     * Render the passwords
82     *
83     * @param string $format
84     * @param Doku_Renderer_metadata $renderer
85     * @param array $data
86     *
87     * @return type boolean is de operatie geslaagd?
88     */
89    public function render($format, Doku_Renderer $renderer, $data) {
90        if('xhtml' === $format) {
91            $this->iterator = 0;
92            $this->parseData($data[0]);
93            for($i=0; $i<$this->getAmount(); $i++) {
94                $renderer->doc .= $this->getPasswordHtml($this->getLength());
95            }
96            return true;
97        } else {
98            return false;
99        }
100    }
101
102    /**
103     * Parse data to filter out variables
104     *
105     * @param string $data
106     *
107     * @return boolean success
108     */
109    private function parseData($data) {
110        $regexAmount = '#amount=(\d*)#i';
111        $regexLength = '#length=(\d*)#i';
112
113        preg_match($regexAmount, $data, $resultAmount);
114        $this->setAmount($resultAmount[1]);
115
116        preg_match($regexLength, $data, $resultLength);
117        $this->setLength($resultLength[1]);
118        return true;
119    }
120
121    /**
122     * Generate the password
123     *
124     * @param int $length lengte
125     *
126     * @return string
127     */
128    private function generatePassword($length) {
129        $password = '';
130        for($j=0; $j < $length; $j++) {
131            $r = rand(0,strlen($this->getAllowedCharacters())-1);
132            $c = substr($this->getAllowedCharacters(), $r, 1);
133            $password .= $c;
134        }
135        return $password;
136    }
137
138    /**
139     * Generate HTML
140     *
141     * @param int $passwordLength length of password
142     *
143     * @return string
144     */
145    private function getPasswordHtml($passwordLength) {
146        $iterator = $this->getIterator();
147        $iteratorHtml = '';
148        if($iterator < 10) {
149            $iteratorHtml .= '0';
150        }
151        $iteratorHtml .= $iterator;
152        return $iteratorHtml
153            . '<input class="inputfield" '
154            . ' type="text" '
155            . ' value="' . $this->generatePassword($passwordLength) . '"'
156            . ' onmouseover="this.select();" '
157            . ' onclick="this.select();" '
158            . ' />'
159            . '<br>';
160    }
161
162    /**
163     * Haal de iterator op
164     *
165     * @return int
166     */
167    private function getIterator() {
168        return ++$this->iterator;
169    }
170
171    /**
172     * Get the allowed characters
173     *
174     * @return string
175     */
176    private function getAllowedCharacters() {
177        return $this->allowedCharacters;
178    }
179
180    /**
181     * Get the amount of passwords
182     *
183     * @return int
184     */
185    private function getAmount() {
186        return $this->amount;
187    }
188
189    /**
190     * Set the amount of passwords
191     *
192     * @param int $amount
193     */
194    private function setAmount($amount) {
195        $amount = (int) $amount;
196        if($amount > 0) {
197            $this->amount = $amount;
198        }
199    }
200
201    /**
202     * Get the lenght of the password
203     *
204     * @return int
205     */
206    private function getLength() {
207        return $this->length;
208    }
209
210    /**
211     * Set the lenght of the password
212     *
213     * @param int $length
214     */
215    private function setLength($length) {
216        $length = (int) $length;
217        if($length > 0) {
218            $this->length = $length;
219        }
220    }
221
222}