]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/WikiPoll.php
private
[SourceForge/phpwiki.git] / lib / plugin / WikiPoll.php
1 <?php
2
3 /*
4  * Copyright 2004 $ThePhpWikiProgrammingTeam
5  * Copyright 2008 Marc-Etienne Vargenau, Alcatel-lucent
6  *
7  * This file is part of PhpWiki.
8  *
9  * PhpWiki is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * PhpWiki is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 /**
24  * This plugin provides configurable polls.
25  *
26  * Usage:
27 <<WikiPoll require_all=0 require_least=2
28 question[1]="Do you like PhpWiki?"
29 answer[1][1]="Yes" answer[1][2]="Do not know" answer[1][3]="No"
30 question[2]="Do you have PhpWiki installed by your own?"
31 answer[2][1]="Yes" answer[2][2]="No"
32 question[3]="Did you install any other wiki engine?"
33 answer[3][1]="Yes" answer[3][2]="No"
34 question[4]="What wiki engine do you like most?"
35 answer[4][1]="c2Wiki" answer[4][2]="MoinMoin" answer[4][3]="PhpWiki"
36 answer[4][4]="usemod" answer[4][5]="Twiki" answer[4][5]="guiki"
37 answer[4][6]="Mediawiki" answer[4][7]="Other"
38 question[5]="Which PhpWiki version do you use?"
39 answer[5][1]="1.2.x" answer[5][2]="1.3.1-12" answer[5][3]="1.3.13"
40 answer[5][4]="1.3.14"
41 >>
42  *
43  * Administration:
44  * <<WikiPoll page=PhpWikiPoll admin=1 >>
45  * and protect this page properly (e.g. PhpWikiPoll/Admin)
46  *
47  * TODO:
48  *     admin page (view and reset statistics)
49  *     for now only radio, support checkboxes (multiple selections) also?
50  *
51  * Author: ReiniUrban
52  */
53
54 class WikiPlugin_WikiPoll
55     extends WikiPlugin
56 {
57     var $_args;
58
59     function getName()
60     {
61         return _("WikiPoll");
62     }
63
64     function getDescription()
65     {
66         return _("Enable configurable polls.");
67     }
68
69     function getDefaultArguments()
70     {
71         return array('page' => '[pagename]',
72             'admin' => false,
73             'require_all' => 1, // 1 if all questions must be answered
74             'require_least' => 0, // how many at least
75         );
76     }
77
78     function getArgs($argstr, $request = false, $defaults = false)
79     {
80         if ($defaults === false)
81             $defaults = $this->getDefaultArguments();
82         //Fixme: on POST argstr is empty
83         $args = array();
84         list ($argstr_args, $argstr_defaults) = $this->parseArgStr($argstr);
85         if (isset($argstr_args["question_1"])) {
86             $args['question'] = $this->str2array("question", $argstr_args);
87             $args['answer'] = array();
88             for ($i = 0; $i <= count($args['question']); $i++) {
89                 if ($array = $this->str2array(sprintf("%s_%d", "answer", $i), $argstr_args))
90                     $args['answer'][$i] = $array;
91             }
92         }
93
94         if (!empty($defaults))
95             foreach ($defaults as $arg => $default_val) {
96                 if (isset($argstr_args[$arg]))
97                     $args[$arg] = $argstr_args[$arg];
98                 elseif ($request and ($argval = $request->getArg($arg)) !== false)
99                     $args[$arg] = $argval; elseif (isset($argstr_defaults[$arg]))
100                     $args[$arg] = (string)$argstr_defaults[$arg]; else
101                     $args[$arg] = $default_val;
102
103                 if ($request)
104                     $args[$arg] = $this->expandArg($args[$arg], $request);
105
106                 unset($argstr_args[$arg]);
107                 unset($argstr_defaults[$arg]);
108             }
109
110         foreach (array_merge($argstr_args, $argstr_defaults) as $arg => $val) {
111             if (!preg_match("/^(answer_|question_)/", $arg))
112                 trigger_error(sprintf(_("Argument ā€œ%sā€ not declared by plugin."),
113                     $arg), E_USER_NOTICE);
114         }
115
116         return $args;
117     }
118
119     function handle_plugin_args_cruft($argstr, $args)
120     {
121         $argstr = str_replace("\n", " ", $argstr);
122         $argstr = str_replace(array("[", "]"), array("_", ""), $argstr);
123         $this->_args = $this->getArgs($argstr, $GLOBALS['request']);
124         return;
125     }
126
127     private function str2array($var, $obarray = false)
128     {
129         if (!$obarray) $obarray = $GLOBALS;
130         $i = 0;
131         $array = array();
132         $name = sprintf("%s_%d", $var, $i);
133         if (isset($obarray[$name])) $array[$i] = $obarray[$name];
134         do {
135             $i++;
136             $name = sprintf("%s_%d", $var, $i);
137             if (isset($obarray[$name])) $array[$i] = $obarray[$name];
138         } while (isset($obarray[$name]));
139         return $array;
140     }
141
142     function run($dbi, $argstr, &$request, $basepage)
143     {
144         if (!isset($_SERVER))
145             $_SERVER =& $GLOBALS['HTTP_SERVER_VARS'];
146         $request->setArg('nocache', 'purge');
147         $args = $this->getArgs($argstr, $request);
148         if (!$args['page']) {
149             return $this->error(sprintf(_("A required argument ā€œ%sā€ is missing."), 'page'));
150         }
151         if (!empty($args['admin']) and $request->_user->isAdmin()) {
152             // reset statistics
153             return $this->doPollAdmin($dbi, $request, $page);
154         }
155         extract($this->_args);
156         $page = $dbi->getPage($args['page']);
157         // check ip and last visit
158         $poll = $page->get("poll");
159         $ip = $_SERVER['REMOTE_ADDR'];
160         $disable_submit = false;
161         if (isset($poll['ip'][$ip]) and ((time() - $poll['ip'][$ip]) < 20 * 60)) {
162             //view at least the result or disable the Go button
163             $html = HTML(HTML::strong(
164                 _("Sorry! You must wait at least 20 minutes until you can vote again!")));
165             $html->pushContent($this->doPoll($page, $request, $request->getArg('answer'), true));
166             return $html;
167         }
168
169         $poll['ip'][$ip] = time();
170         // purge older ip's
171         foreach ($poll['ip'] as $ip => $time) {
172             if ((time() - $time) > 21 * 60)
173                 unset($poll['ip'][$ip]);
174         }
175         $html = HTML::form(array('action' => $request->getPostURL(),
176             'method' => 'post'));
177
178         if ($request->isPost()) {
179             // checkme: check if all answers are answered
180             if ($request->getArg('answer') and (
181                 ($args['require_all'] and
182                     count($request->getArg('answer')) == count($question))
183                     or
184                     ($args['require_least'] and
185                         count($request->getArg('answer')) >= $args['require_least']))
186             ) {
187                 $page->set("poll", $poll);
188                 // update statistics and present them the user
189                 return $this->doPoll($page, $request, $request->getArg('answer'));
190             } else {
191                 $html->pushContent(HTML::p(HTML::strong(_("Not enough questions answered!"))));
192             }
193         }
194
195         $init = isset($question[0]) ? 0 : 1;
196         for ($i = $init; $i <= count($question); $i++) {
197             if (!isset($question[$i])) break;
198             $q = $question[$i];
199             if (!isset($answer[$i]))
200                 trigger_error(fmt("Missing %s for %s", "answer" . "[$i]", "question" . "[$i]"),
201                     E_USER_ERROR);
202             $a = $answer[$i];
203             if (!is_array($a)) {
204                 // a simple checkbox
205                 $html->pushContent(HTML::p(HTML::strong($q)));
206                 $html->pushContent(HTML::div(
207                     HTML::input(array('type' => 'checkbox',
208                         'name' => "answer[$i]",
209                         'value' => 1)),
210                     HTML::raw("&nbsp;"), $a));
211             } else {
212                 $row = HTML();
213                 for ($j = 0; $j <= count($a); $j++) {
214                     if (isset($a[$j]))
215                         $row->pushContent(HTML::div(
216                             HTML::input(array('type' => 'radio',
217                                 'name' => "answer[$i]",
218                                 'value' => $j)),
219                             HTML::raw("&nbsp;"), $a[$j]));
220                 }
221                 $html->pushContent(HTML::p(HTML::strong($q)), $row);
222             }
223         }
224         if (!$disable_submit)
225             $html->pushContent(HTML::p(
226                 HTML::input(array('type' => 'submit',
227                     'name' => "WikiPoll",
228                     'value' => _("OK"))),
229                 HTML::input(array('type' => 'reset',
230                     'name' => "reset",
231                     'value' => _("Reset")))));
232         else
233             $html->pushContent(HTML::p(), HTML::strong(
234                 _("Sorry! You must wait at least 20 minutes until you can vote again!")));
235         return $html;
236     }
237
238     private function bar($percent)
239     {
240         global $WikiTheme;
241         return HTML(HTML::img(array('src' => $WikiTheme->getImageUrl('leftbar'),
242                 'alt' => '<')),
243             HTML::img(array('src' => $WikiTheme->getImageUrl('mainbar'),
244                 'alt' => '-',
245                 'width' => sprintf("%02d", $percent),
246                 'height' => 14)),
247             HTML::img(array('src' => $WikiTheme->getImageUrl('rightbar'),
248                 'alt' => '>')));
249     }
250
251     private function doPoll($page, $request, $answers, $readonly = false)
252     {
253         $question = $this->_args['question'];
254         $answer = $this->_args['answer'];
255         $html = HTML::table(array('cellspacing' => 2));
256         $init = isset($question[0]) ? 0 : 1;
257         for ($i = $init; $i <= count($question); $i++) {
258             if (!isset($question[$i])) break;
259             $poll = $page->get('poll');
260             @$poll['data']['all'][$i]++;
261             $q = $question[$i];
262             if (!isset($answer[$i]))
263                 trigger_error(fmt("Missing %s for %s", "answer" . "[$i]", "question" . "[$i]"),
264                     E_USER_ERROR);
265             if (!$readonly)
266                 $page->set('poll', $poll);
267             $a = $answer[$i];
268             $result = (isset($answers[$i])) ? $answers[$i] : -1;
269             if (!is_array($a)) {
270                 $checkbox = HTML::input(array('type' => 'checkbox',
271                     'name' => "answer[$i]",
272                     'value' => $a));
273                 if ($result >= 0)
274                     $checkbox->setAttr('checked', "checked");
275                 if (!$readonly)
276                     list($percent, $count, $all) = $this->storeResult($page, $i, $result ? 1 : 0);
277                 else
278                     list($percent, $count, $all) = $this->getResult($page, $i, 1);
279                 $print = sprintf(_("  %d%% (%d/%d)"), $percent, $count, $all);
280                 $html->pushContent(HTML::tr(HTML::th(array('colspan' => 4, 'align' => 'left'), $q)));
281                 $html->pushContent(HTML::tr(HTML::td($checkbox),
282                     HTML::td($a),
283                     HTML::td($this->bar($percent)),
284                     HTML::td($print)));
285             } else {
286                 $html->pushContent(HTML::tr(HTML::th(array('colspan' => 4, 'align' => 'left'), $q)));
287                 $row = HTML();
288                 if (!$readonly)
289                     $this->storeResult($page, $i, $answers[$i]);
290                 for ($j = 0; $j <= count($a); $j++) {
291                     if (isset($a[$j])) {
292                         list($percent, $count, $all) = $this->getResult($page, $i, $j);
293                         $print = sprintf(_("  %d%% (%d/%d)"), $percent, $count, $all);
294                         $radio = HTML::input(array('type' => 'radio',
295                             'name' => "answer[$i]",
296                             'value' => $j));
297                         if ($result == $j)
298                             $radio->setAttr('checked', "checked");
299                         $row->pushContent(HTML::tr(HTML::td($radio),
300                             HTML::td($a[$j]),
301                             HTML::td($this->bar($percent)),
302                             HTML::td($print)));
303                     }
304                 }
305                 $html->pushContent($row);
306             }
307         }
308         if (!$readonly)
309             return HTML(HTML::h3(_("The result of this poll so far:")), $html, HTML::p(_("Thanks for participating!")));
310         else
311             return HTML(HTML::h3(_("The result of this poll so far:")), $html);
312
313     }
314
315     private function getResult($page, $i, $j)
316     {
317         $poll = $page->get("poll");
318         @$count = $poll['data']['count'][$i][$j];
319         @$all = $poll['data']['all'][$i];
320         $percent = sprintf("%d", $count * 100.0 / $all);
321         return array($percent, $count, $all);
322     }
323
324     private function storeResult($page, $i, $j)
325     {
326         $poll = $page->get("poll");
327         if (!$poll) {
328             $poll = array('data' => array('count' => array(),
329                 'all' => array()));
330         }
331         @$poll['data']['count'][$i][$j]++;
332         //@$poll['data']['all'][$i];
333         $page->set("poll", $poll);
334         $percent = sprintf("%d", $poll['data']['count'][$i][$j] * 100.0 / $poll['data']['all'][$i]);
335         return array($percent, $poll['data']['count'][$i][$j], $poll['data']['all'][$i]);
336     }
337
338 }
339
340 // Local Variables:
341 // mode: php
342 // tab-width: 8
343 // c-basic-offset: 4
344 // c-hanging-comment-ender-p: nil
345 // indent-tabs-mode: nil
346 // End: