poll.php
1: <?php
2: /****************************************************************************
3: * DRBPoll
4: * http://www.dbscripts.net/poll/
5: *
6: * Copyright � 2007-2009 Don B
7: ****************************************************************************/
8:
9: $PREVENT_DUPLICATE_VOTES = TRUE;
10: $SHOW_COUNTS = TRUE;
11:
12: require_once(dirname(__FILE__) . '/config.php');
13:
14: function show_vote_control($poll_id) {
15: global $POLL_URL;
16: global $VOTE_STRING;
17: global $VOTE_PARAM_NAME;
18: global $VOTE_LIST_DEFAULT_LABEL;
19: global $VALID_POLLS;
20: global $POLL_ID_PARAM_NAME;
21: global $SUBMIT_BUTTON_STRING;
22: global $VIEW_RESULTS_STRING;
23:
24: // Validate parameters
25: if(!is_valid_poll_id($poll_id)) {
26: die('ERROR: An invalid poll ID was submitted.');
27: }
28:
29: $poll = $VALID_POLLS[$poll_id];
30:
31: // Output vote control
32: echo("<div class=\"voteContainer\">\r\n");
33: echo("\t<form class=\"vote\" method=\"post\" action=\"" . $POLL_URL . "vote.php\">\r\n");
34: echo("\t<fieldset>\r\n");
35: if(!empty($poll->legend) && sizeof($poll->legend) > 0) {
36: echo("\t<legend>" . htmlspecialchars($poll->legend) . "</legend>\r\n");
37: }
38: echo("\t<p class=\"question\">\r\n");
39: echo("\t\t" . htmlspecialchars($poll->question) . "\r\n");
40: echo("\t</p>\r\n\t<p>\r\n");
41:
42: global $CONTROL_RADIOBUTTONS;
43: global $CONTROL_COMBOBOX;
44: if($poll->control_type === $CONTROL_RADIOBUTTONS) {
45:
46: // Iterate through poll values
47: foreach ($poll->values as $value_id => $description) {
48: echo("\t\t<input type=\"radio\" name=\"" . htmlspecialchars($VOTE_PARAM_NAME) .
49: "\" value=\"" . htmlspecialchars($value_id) . "\" /> ");
50: if( isset($poll->urls[$value_id]) && !empty($poll->urls[$value_id]) ) {
51: echo("<a href=\"" . htmlspecialchars($poll->urls[$value_id])
52: . "\" target=\"_blank\" rel=\"nofollow\">"
53: . htmlspecialchars($description) . "</a>");
54: } else {
55: echo(htmlspecialchars($description));
56: }
57: echo("<br />\r\n");
58: }
59:
60: echo("\t</p>\r\n\t<p>\r\n");
61:
62: } else if($poll->control_type === $CONTROL_COMBOBOX) {
63:
64: echo("\t\t" . htmlspecialchars($VOTE_STRING) . "\r\n");
65:
66: echo("\t\t<select name=\"" . htmlspecialchars($VOTE_PARAM_NAME) . "\">\r\n");
67: echo("\t\t\t<option value=\"\">" . htmlspecialchars($VOTE_LIST_DEFAULT_LABEL) . "</option>\r\n");
68:
69: // Iterate through poll values
70: foreach ($poll->values as $value_id => $description) {
71: echo("\t\t\t<option value=\"" . htmlspecialchars($value_id) . "\">");
72: echo(htmlspecialchars($description));
73: echo("</option>\r\n");
74: }
75: echo("\t\t</select>\r\n");
76:
77: } else {
78:
79: die('ERROR: Invalid control type.');
80:
81: }
82: echo("\t\t<input type=\"hidden\" name=\"" . htmlspecialchars($POLL_ID_PARAM_NAME) . "\" value=\"" . htmlspecialchars($poll_id) . "\" />\r\n");
83: echo("\t\t<input type=\"submit\" value=\"" . htmlspecialchars($SUBMIT_BUTTON_STRING) . "\" class=\"submit\" />\r\n");
84: echo("\t</p>\r\n\t<p class=\"currentResults\">\r\n");
85:
86: // Show results link
87: echo("\t\t<a href=\"" . $POLL_URL . "results.php?" . htmlspecialchars($POLL_ID_PARAM_NAME) . "=" . htmlspecialchars($poll_id) . "\">" . htmlspecialchars($VIEW_RESULTS_STRING) . "</a>\r\n");
88:
89: echo("\t</p>\r\n");
90: echo("\t</fieldset>\r\n");
91: echo("\t</form>\r\n");
92: echo("</div>\r\n");
93:
94: }
95:
96: function show_poll_results($poll_id) {
97:
98: // Validate parameters
99: if(!is_valid_poll_id($poll_id)) {
100: die('ERROR: An invalid poll ID was submitted.');
101: }
102:
103: // Get poll object
104: global $VALID_POLLS;
105: $poll = $VALID_POLLS[$poll_id];
106:
107: // Get vote summary
108: $summarylist = vote_summary_list($poll_id);
109: if($summarylist !== FALSE) {
110: $totalVotes = $summarylist[0];
111: $largest_count = find_largest_vote_value_count($summarylist);
112: } else {
113: $totalVotes = 0;
114: $largest_count = 0;
115: }
116:
117: // Show question
118: echo("\t<p class=\"question\">\r\n");
119: echo("\t\t" . htmlspecialchars($poll->question) . "\r\n");
120: echo("\t</p>\r\n");
121:
122: // Start table for results
123: echo("<table class=\"pollTable\">\r\n");
124:
125: // Iterate through poll values
126: $barNumber = 1;
127: global $MAX_POLL_BAR_WIDTH;
128: global $SHOW_COUNTS;
129: foreach($poll->values as $value_id => $description) {
130:
131: // Find vote count for this value
132: $summary_row = find_vote_value_summary($value_id, $summarylist);
133:
134: if($summary_row === FALSE) {
135: $count = 0;
136: } else {
137: $count = $summary_row[1];
138: }
139:
140: $percentage = (($totalVotes > 0)?($count / $totalVotes):0);
141: $bar_percentage = (($largest_count > 0)?($count / $largest_count):0);
142: echo("\t<tr>");
143: echo("<td class=\"pollDescriptionCell\">");
144: if( isset($poll->urls[$value_id]) && !empty($poll->urls[$value_id]) ) {
145: echo("<a href=\"" . htmlspecialchars($poll->urls[$value_id])
146: . "\" target=\"_blank\" rel=\"nofollow\">"
147: . htmlspecialchars($description) . "</a>");
148: } else {
149: echo(htmlspecialchars($description));
150: }
151: echo("</td>");
152: echo("<td class=\"pollBarCell\">");
153: if($count > 0) {
154: echo("<div class=\"pollBar\" id=\"pollBar" . ($barNumber++) . "\" style=\"width:" . round($MAX_POLL_BAR_WIDTH * $bar_percentage, 0) . "px;\"></div>");
155: }
156: echo("</td>");
157: echo("<td class=\"pollCountCell\">" . (($SHOW_COUNTS === TRUE)?$count . " (":"") . (($count > 0)?round($percentage * 100, 2):0) . "%" . (($SHOW_COUNTS === TRUE)?")":"") . "</td>");
158: echo("</tr>\r\n");
159:
160: }
161:
162: echo("</table>");
163:
164: if($SHOW_COUNTS === TRUE) {
165: global $NUMBER_OF_VOTES_STRING;
166: $numberOfVotesString = sprintf($NUMBER_OF_VOTES_STRING, $totalVotes);
167: echo("<p>" . htmlspecialchars($numberOfVotesString) . "</p>");
168: }
169:
170: }
171:
172: function the_current_poll_results() {
173: global $requested_poll_id;
174: show_poll_results($requested_poll_id);
175: }
176:
177: function the_return_to_url() {
178: global $requested_poll_id;
179: global $VALID_POLLS;
180: $poll = $VALID_POLLS[$requested_poll_id];
181:
182: if(!empty($poll->returnToURL)) {
183: echo $poll->returnToURL;
184: } else {
185: die("ERROR: Return to URL not defined for this poll.");
186: }
187:
188: }
189:
190: function smarter_is_int($val) {
191: return (is_numeric($val)?intval($val)==$val:FALSE);
192: }
193:
194: function is_valid_poll_id($poll_id) {
195: global $VALID_POLLS;
196: return (!empty($poll_id) && preg_match('/^[a-zA-Z0-9]+$/D', $poll_id) === 1 && array_key_exists($poll_id, $VALID_POLLS));
197: }
198:
199: function is_valid_vote($poll, $vote_value_id) {
200: return (!empty($vote_value_id) && preg_match('/^[a-zA-Z0-9]+$/D', $vote_value_id) === 1 && array_key_exists($vote_value_id, $poll->values));
201: }
202:
203: function get_vote_count($summarylist) {
204:
205: // Get vote count from summary
206: if($summarylist === FALSE || count($summarylist) < 1) {
207: return 0;
208: } else {
209: return $summarylist[0];
210: }
211:
212: }
213:
214: function add_new_vote($poll_id, $vote_value_id) {
215: global $vote_error_message;
216:
217: // Make sure vote wasn't left blank
218: if(empty($vote_value_id)) {
219: global $NO_VOTE_SELECTED_ERROR_MSG;
220: $vote_error_message = $NO_VOTE_SELECTED_ERROR_MSG;
221: return FALSE;
222: }
223:
224: // Validate poll ID
225: if(!is_valid_poll_id($poll_id)) {
226: die('ERROR: An invalid poll ID was submitted.');
227: }
228:
229: // Get poll object
230: global $VALID_POLLS;
231: $poll = $VALID_POLLS[$poll_id];
232:
233: // Validate vote value ID
234: if(!is_valid_vote($poll, $vote_value_id) ) {
235: die('ERROR: An invalid vote was submitted.');
236: }
237:
238: // Check for duplicate vote attempt
239: $ipaddress = $_SERVER['REMOTE_ADDR'];
240: global $PREVENT_DUPLICATE_VOTES;
241: if($PREVENT_DUPLICATE_VOTES && has_voted($poll_id, $ipaddress)) {
242: global $DUPLICATE_VOTE_ERROR_MSG;
243: $vote_error_message = $DUPLICATE_VOTE_ERROR_MSG;
244: return FALSE;
245: }
246:
247: // Add vote
248: vote_history_add($poll_id, $ipaddress, $vote_value_id);
249: vote_summary_add($poll_id, $vote_value_id);
250:
251: return TRUE;
252: }
253:
254: function vote_summary_file_path($id) {
255: return dirname(__FILE__) . '/data/summary_' . $id . '.dat';
256: }
257:
258: function vote_history_file_path($id) {
259: return dirname(__FILE__) . '/data/history_' . $id . '.dat';
260: }
261:
262: function vote_summary_list($poll_id) {
263:
264: // Load existing
265: $summarylist = @file(vote_summary_file_path($poll_id));
266: if($summarylist !== FALSE) {
267: $summarylist = array_map("trim", $summarylist);
268: }
269: return $summarylist;
270:
271: }
272:
273: function find_vote_value_summary($vote_value_id, $summarylist) {
274:
275: if($summarylist === FALSE) return FALSE;
276: for($i = 1; $i < sizeof($summarylist); $i++) {
277:
278: $summary_row = explode_history($summarylist[$i]);
279: if($summary_row[0] === ("" . $vote_value_id)) {
280: return $summary_row;
281: }
282:
283: }
284: return FALSE;
285:
286: }
287:
288: function find_largest_vote_value_count($summarylist) {
289:
290: $largest_count = 0;
291: for($i = 1; $i < sizeof($summarylist); $i++) {
292:
293: $summary_row = explode_history($summarylist[$i]);
294: if($summary_row[1] > $largest_count) {
295: $largest_count = $summary_row[1];
296: }
297:
298: }
299: return $largest_count;
300:
301: }
302:
303: function vote_summary_add($poll_id, $vote_value_id) {
304:
305: // Get existing poll summary
306: $summarylist = vote_summary_list($poll_id);
307: $vote_summary_file_path = vote_summary_file_path($poll_id);
308:
309: // Create summary file if it doesn't exist
310: if(!file_exists($vote_summary_file_path)) {
311: if(@touch($vote_summary_file_path) === FALSE) {
312: die("Unable to create summary file");
313: }
314: }
315:
316: // Open summary file
317: $summary_fp = @fopen($vote_summary_file_path, "r+");
318: if($summary_fp === FALSE) {
319: die("Unable to open summary file for writing");
320: }
321: if(@flock($summary_fp, LOCK_EX) === FALSE) {
322: @fclose($summary_fp);
323: die("Unable to lock summary file");
324: }
325: if(@ftruncate($summary_fp, 0) === FALSE) {
326: @fclose($summary_fp);
327: die("Unable to truncate summary file");
328: }
329:
330: // Update total vote count
331: if($summarylist === FALSE || count($summarylist) < 1) {
332: $count = 1;
333: } else {
334: $count = $summarylist[0] + 1;
335: }
336: fputs($summary_fp, $count . "\n");
337:
338: // Add vote to value total
339: if($summarylist === FALSE) {
340:
341: // First vote
342: $out = $vote_value_id . "|1";
343: fputs($summary_fp, $out . "\n");
344:
345: } else {
346:
347: // Iterate through existing vote values
348: $vote_counted = FALSE;
349: for($i = 1; $i < sizeof($summarylist); $i++) {
350:
351: $summary_row = explode_history($summarylist[$i]);
352: if($summary_row[0] === $vote_value_id) {
353:
354: // Increase vote count for this value
355: $summary_row[1] += 1;
356: $vote_counted = TRUE;
357:
358: }
359:
360: // Write out new vote count for this id
361: $out = implode("|", $summary_row);
362: fputs($summary_fp, $out . "\n");
363:
364: }
365:
366: if($vote_counted === FALSE) {
367:
368: // This is the first vote for this value
369: $out = $vote_value_id . "|1";
370: fputs($summary_fp, $out . "\n");
371:
372: }
373:
374:
375: }
376: fclose($summary_fp);
377:
378: }
379:
380: function vote_history_add($poll_id, $ipaddress, $vote_value_id) {
381:
382: // Open/create history file
383: $history_fp = @fopen(vote_history_file_path($poll_id), "a");
384: if($history_fp === FALSE) {
385: die("Unable to open history file for writing");
386: }
387:
388: // Add IP address and vote to history
389: @flock($history_fp, LOCK_EX);
390: fputs($history_fp, $ipaddress . "|" . $vote_value_id . "\n");
391: fclose($history_fp);
392:
393: }
394:
395: function explode_history($line) {
396: return array_map("trim", explode("|", $line));
397: }
398:
399: function vote_history_list($poll_id) {
400:
401: // Load existing vote history
402: $summarylist = @file(vote_history_file_path($poll_id));
403: if($summarylist !== FALSE) {
404: $summarylist = array_map("explode_history", $summarylist);
405: }
406:
407: return $summarylist;
408:
409: }
410:
411: function has_voted($poll_id, $ipaddress) {
412:
413: // Find vote history
414: $vote_history_list = vote_history_list($poll_id);
415: if($vote_history_list !== FALSE) {
416: return( find_vote_history(trim($ipaddress), $vote_history_list) !== FALSE );
417: } else {
418: return FALSE;
419: }
420:
421: }
422:
423: function find_vote_history($ipaddress, $list) {
424:
425: // Search vote history for this IP address
426: if(!empty($list)) {
427: for($i = 0; $i < count($list); $i++) {
428: if($list[$i][0] == $ipaddress) return $list[$i];
429: }
430: }
431: return FALSE;
432:
433: }
434:
435: /* DO NOT REMOVE OR HIDE THE CREDIT BELOW, PER LICENSE! */
436: function the_credits() {
437: echo("<div class=\"credit\">Powered by DRBPoll · <a href=\"http://www.dbscripts.net/hosting/\">PHP Hosting</a></div>\n");
438: }
439: /* END CREDIT */
440:
441: ?>