Afstemningsboks med PHP/MySQL

Tags:    php
Skrevet af Bruger #1 @ 26.12.2002
Afstemningsboks med PHP/MySQL

Du kender dem sikkert fra en masse sites, bl.a. Udvikleren.dk: Den fine lille afstemningsboks, der med sine mere eller mindre relevante spørgsmål, sørger for at brugeren får lov til at give sin mening til kende, dog på en anonym måde. Her på Udvikleren.dk er afstemningen brugerbaseret. Det vil sige at alle brugere af sitet, der er logget ind, har mulighed for at stemme én gang. Folk der ikke er logget ind, kan ikke stemme. Dette kan man godt tillade sig at gøre på et site som Udvikleren.dk, hvor der efterhånden er rimeligt mange brugere. Desuden giver det også en langt større præcision, når en bruger kun kan stemme én gang, uden at kunne snyde med cookies, IP adresser eller lignende.

Det er ret let at lave en brugerbaseret afstemningsboks, faktisk en del lettere end at lave den cookie og/eller IP baseret, men det er ikke praktisk til specielt mange sites. Den afstemningsboks vi laver her vil derfor være baseret på cookies. Dvs. at man KAN snyde hvis man vil, men da de færreste brugere synes at det er voldsomt morsomt at bruge tid på at sidde og fifle med cookies bare for at snyde en afstemning, går det nok an.

Den afstemningsboks vi laver bliver nogenlunde simpel: En database tabel der indeholder de forskellige afstemninger, samt en tabel der indeholder alle stemmerne. Denne artikel er i øvrigt baseret meget kraftigt på kode som jeg har skrevet til Udviklerens afstemningssystem.

Database stuff...


Vi starter med at oprette de to tabeller vi skal bruge. Jeg vil lige nævne at denne artikel kræver nogenlunde PHP/MySQL kvalifikationer, så jeg vil ikke skære tingene alt for meget ud i pap.


CREATE TABLE polls (
id int(5) NOT NULL auto_increment,
question varchar(255) default NULL,
numofanswers int(1) default NULL,
answer1 varchar(255) default NULL,
answer2 varchar(255) default NULL,
answer3 varchar(255) default NULL,
answer4 varchar(255) default NULL,
answer5 varchar(255) default NULL,
answer6 varchar(255) default NULL,
answer7 varchar(255) default NULL,
answer8 varchar(255) default NULL,
nowactive int(1) NOT NULL default '0',
PRIMARY KEY (id)
)

CREATE TABLE pollvotes (
id int(10) NOT NULL auto_increment,
pollid int(5) default NULL,
vote int(1) default NULL,
PRIMARY KEY (id)
)


Sådan ser de ud :). Den første tabel holder som sagt styr på afstemningerne. Man kunne jo let have lavet det statisk, så der altid bare var en afstemning, som man selv kunne oprette HTML kode til at vise, og så bare gemme/hente resultaterne i databasen via den sidste tabel. Denne måde giver dog mulighed for at have en aktiv afstemning, og så samtidig have de andre liggende, fx til et afstemningsarkiv. nowactive værdien skal fortælle om den pågældende afstemning er aktiv eller ej. Dette er lidt tricky: enten kan man vælge at holde godt styr på det, og så altid sørge for at kun én række i tabellen har nowactive sat til 1, og det er den aktive afstemning. Så skal man altid huske at sætte de andre til 0. Den slags er jeg jo personligt alt for doven til :). Udviklerens system fungerer derfor ved at den nyeste afstemning (det fortløbende ID angiver jo hvor ny en afstemning er) der er sat til nowactive, er den der vises. Den første metode er nok den ”pæneste” af de 2, og der er sikkert også en 3. løsning der er endnu pænere. Personligt brugere jeg løsning nr. 2 da den passer mig bedst :). Numofanswers fortæller hvor mange svarmuligheder der skal være i den pågældende afstemning. Det kunne måske gøres uden den, ved at kigge i answer felterne og så stoppe når et felt var tomt, men denne løsning er nu noget lettere at implementere, synes jeg. Pollvotes tabellen er ganske simpel. Den består af et fortløbende ID, samt et tal der angiver hvilken poll stemmen gælder for, og til sidst: hvad personen har stemt. Vote feltet er kun sat til 1, da der jo i mit lille system højst er mulighed for 8 svarmuligheder. Har man puttet flere svarmuligheder på den første tabel, skal dette felt eventuelt sættes højere.

At kode..


Okay, tabellerne skulle gerne være oprettet nu, så vi er faktisk klar til at skrive lidt PHP kode. Jeg har personligt lavet det sådan at alt afstemningsrelateret ligger i en fil, i funktioner, der så kan includes og kaldes der hvor jeg har brug for dem. I kan kalde filen for pollfunctions.php, og smide følgende funktioner ind i, som jeg naturligvis forklarer. Lad os starte med lidt variabler, der bruges af de forskellige funktioner:


$dbtable_polls = "polls";
$dbtable_pollvotes = "pollvotes";
$cookieprefix = "mypoll";
$redirectto = "http://www.udvikleren.dk";


De første to variabler fortæller sådan set bare hvad vores databasetabeller hedder. Ikke så meget pjat der :). Næste variabel er det prefix der sættes foran de cookies som scriptet sætter. Det kunne muligvis godt undværes, med da jeg skrev systemet ville jeg gerne være sikker på at det kunne bruges flere forskellige steder, og så kunne det måske være meget smart at prefixe de cookies der sættes. Fx hedder er variablen sat til ”udv” på Udvikleren.dk. Så ved man hvor de kommer fra. Den sidste variabel fortæller scriptet hvor der skal vidersendes til, når der er stemt. Selvom man viser afstemning og resultat på samme side, er det nødvendigt lige at redirecte engang, så browseren får mulighed for at læse de cookies der lige er sat.


if($_POST[do_vote] and $_POST[pid] and $_POST[vid]) {
CastVote($_POST[pid], $_POST[vid]);
}


Den sidste del af koden, der ikke ligger i en funktion. Denne del holder simpelthen øje med om afstemningen bliver brugt. Hvis den gør det, vil de 3 variabler der tjekkes alle sammen have en værdi, og så er det bare med at kaste en stemme. Det skal dog lige siges at selv hvis formularen bliver vist, vil CastVote stadig tjekke om der er stemt, for en sikkerheds skyld.


function HaveVoted($pid) {
global $cookieprefix;
if(($_COOKIE[$cookieprefix."vote".$pid]) AND ($_COOKIE[$cookieprefix."poll".$pid] == $pid)) {
return true;
} else {
return false;
}
}


Vi starter med en lille funktion der bruges et par forskellige steder. Den er nu ret simpel. Den fortæller om en person har stemt på en bestemt afstemning eller ej. Der tjekkes ud fra cookies og så ID på afstemningen, som overføres via parametren $pid. Der laves 2 checks: Først ser vi om brugeren har en cookie fra vores script med en vote i. Derefter ser vi om den vote rent faktisk tilhører den afstemning som er i gang nu. På den måde vil det være muligt at vise 2 forskellige afstemninger samtidig, uden at de konflikter med hinanden.


function CastVote($pid, $vote) {
global $dbtable_pollvotes; global $cookieprefix; global $redirectto;
if(HaveVoted($pid) != true) {
$addvote = mysql_query("insert into $dbtable_pollvotes (pollid, vote) values ('$pid','$vote')");
setcookie($cookieprefix."vote".$pid, $vote, time()+999999999);
setcookie($cookieprefix."poll".$pid, $pid, time()+999999999);
header("location: $redirectto");
}
}


CastVote funktionen tager ID på den afstemning der skal stemmes på, samt nummeret på det svar der stemmes på. Der tjekkes om personen måske allerede har stemt, og hvis det ikke er tilfældet, tilføjes stemmen til databasen, der sættes et par cookies der fortæller det, og der redirectes så.


function ShowPoll($pid) {
global $dbtable_polls;
$query = mysql_query("select * from $dbtable_polls where id='$pid'");
if(mysql_num_rows($query) > 0)
{
$q = stripslashes(mysql_result($query, 0, "question"));
$num = mysql_result($query, 0, "numofanswers");
$kode .= "<div class=\\"pollquestion\\">$q</div>";
$kode .= "<form action=\\"$_SERVER[PHP_SELF]\\" method=\\"post\\">";
$i = 1;
while($i != $num+1) {
$a = stripslashes(mysql_result($query, 0, "answer".$i));
$kode .= "<div class=\\"pollanswer\\"><input type=\\"radio\\" name=\\"vid\\" value=\\"$i\\" />$a</div>";
$i++;
}
$kode .= "<input type=\\"hidden\\" name=\\"pid\\" value=\\"$pid\\" />";
$kode .= "<br /><input type=\\"submit\\" name=\\"do_vote\\" value=\\" - Stem - \\" class=\\"button\\" />";
$kode .= "</form>";
}
return $kode;
}


En ret vigtig funktion, må man sige :). Den sætter kode sammen til afstemningsboksen, og returnerer det. Funktionen skal kaldes med ID’et på den afstemning man gerne vil vise, og derefter hentes alle de informationer der skal bruges, i databasen. Spørgsmålet og antal af svar hentes ud som værdier. Derefter hentes de forskellige svarmuligheder ud vha. en while-løkke. Den kode der returneres består altså af spørgsmålet, samt radiobuttons med de forskellige svarmuligheder, og så til sidst en knap til at stemme med. Det er jo ganske simpelt! :)


function ShowResults($pid) {
global $dbtable_polls; global $dbtable_pollvotes;
$query = mysql_query("select * from $dbtable_polls where id='$pid'");
$q = stripslashes(mysql_result($query, 0, "question"));
$num = mysql_result($query, 0, "numofanswers");
$kode .= "<div class=\\"pollquestion\\">$q</div>";
$votesquery = mysql_query("select count(id) from $dbtable_pollvotes where pollid='$pid'");
$totalvotes = mysql_result($votesquery, 0, 0);
$i = 1;
$kode .= "<table style=\\"width: 95%;\\" class=\\"text\\">";
while($i != $num+1) {
$a = stripslashes(mysql_result($query, 0, "answer".$i));
$resultquery = mysql_query("select count(id) from $dbtable_pollvotes
where pollid='$pid' and vote='$i'");
$votes = mysql_result($resultquery, 0, 0);
if($votes > 0) {
$average = round(100 * $votes / $totalvotes, 2);
} else {
$average = "0";
}
$kode .= "<tr>";
$kode .= "<td colspan=\\"2\\"><div class=\\"pollanswer\\">$a:</div></td>";
$kode .= "</tr><tr>";
$kode .= "<td style=\\"width: 75%;\\"><span class=\\"pollbar\\" style=\\"width: $average%;\\"></td>";
$kode .= "<td></span>  <span style=\\"text-align: right; font-weight: bold;\\">$average%</span></td>";
$kode .= "</tr>";
$i++;
}
$kode .= "</table>";
$kode .= "<br /><div style=\\"text-align: center;\\">Stemmer i alt:<br /><b>$totalvotes</b></div>";
return $kode;
}


Sidste funktion, til at vise resultatet af en afstemning. Den fungerer egentlig ret meget på samme måde som når vi gerne vil vise en afstemningsboks, bortset fra at der skal hentes lidt flere data (vi går ind i tabellen med stemmerne og finder ud af hvad der er stemt på), og at vi viser det som et resultat frem for en egentlig afstemning. Jeg har lidt simpel tabel/CSS på, for at det kommer til at se nogenlunde pænt ud. Desuden bruger jeg specifikt pollbar CSS classen til at vise en fin bar med resultatet. I kan se den ved at kigge i Udvikleren.dk’s stylesheet, eller lave en selv :)

Færdig?


Så er vi jo faktisk færdige.. eller er vi? Arh, ikke helt. Godt nok har vi lavet en masse funktioner, men vi har jo ikke brugt dem til noget endnu. Så lad os oprette en lille test PHP fil, og blære os lidt med hvor lidt kode der nu skal til for at få vist en 100% funktionsdygtig afstemningsboks:


<?
// Der SKAL være en åben MySQL forbindelse allerede her
include("pollfunctions.php");
?>


Den del skal placeres helt øverst i dit dokument, da setcookie og header kræver at der ikke er udskrevet noget som helst når de kaldes.


$pid = 1; // $pid kan som sagt hentes ud af databasen, eller den kan bare sættes manuelt som her
if(HaveVoted($pid) == true) {
echo ShowResults($pid);
} else {
echo ShowPoll($pid);
}


Det var vist alt for denne gang. Nu skulle vi gerne have en fin afstemningsboks, der kan det meste af det man har brug for. Der er faktisk meget få ændringer i forhold til den i kan se og prøve her på Udvikleren.dk. God fornøjelse med afstemningerne :)
null



Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (24)

User
Bruger #2527 @ 06.02.03 13:02
Er det kun mig der ik kan få den til at virke?

Er det en "copy 'n' paste" artikel eller skal man selv kalde funtionerne??
User
Bruger #2322 @ 15.02.03 16:18
Lidt kritik uden at have testet poll'en.

Først ville jeg ikke lave db'en (polls) på den måde, da det giver et problem hvis du har i sinde at lave over 8 svar muligheder.

så istedet ville jeg bygge den op ca. således :
lave en :

CREATE TABLE pollQuestion (
id INT( 9 ) NOT NULL AUTO_INCREMENT,
question TINYTEXT NOT NULL ,
PRIMARY KEY (id)
);

og en :

CREATE TABLE pollAnswers (

id INT( 9 ) NOT NULL AUTO_INCREMENT,
questionID INT( 9 ) NOT NULL ,
answer TINYTEXT NOT NULL ,
results INT( 9 ) NOT NULL ,
PRIMARY KEY (id)
);

questionID er det id som spørgsmålet har i pollQuestion, så derved kan du oprette alle de svar til et spørgsmål du vil, for hvis du fyrer en query af med WHERE questionID = '$x' ORDER BY id ASC;
hvor $x = id fra pollQuestion...

Blot en lille ting der kan bygges videre på.
User
Bruger #3163 @ 21.02.03 19:33
Den vil ikke logge på databasen! Den svare mig sådan her:
Fatal error: Call to undefined function: havevoted() in /customers/najz.dk/najz.dk/httpd.www/index.php on line 3 såå! Tak for hjælpen på forhånd!
User
Bruger #1330 @ 26.02.03 15:17
Steen D. Christensen, smid det i forumet, og koden på www.pastebin.com så er der nok nogen der gerne vil hjælpe. :)
(Husk selvfølgelig lige at smide et link til denne artikel så de kan se hvor det er fra)
:)
User
Bruger #1330 @ 26.02.03 15:18
Men nice Kasper! :)
Har dog ikke testet det, men god artikel :)
User
Bruger #4086 @ 17.06.03 22:47
God og gennemarbejdet artikel. Jeg gir den 5 for den gode indats du har gjort ved, at forklare alle ting i detaljer.
User
Bruger #4146 @ 29.06.03 18:22
Den virker jo af hat, Kasper det er ikek så smart at skrive en artikel om noget der ikke virker :|...
trorede ellers lige at jeg kunne få en god Afstemningsboks :@
/Lyn-ild (www.lynild.dk)
User
Bruger #4346 @ 21.08.03 11:39
skod aktile ! du lave ikke en total liste over den fil der ska bruge lige fra starten a <html> til slut </html> :S
User
Bruger #3884 @ 23.08.03 19:57
$kode .= "<td colspan="2"><div class="pollanswer">$a:</div></td>"; <-- det kan man ik
User
Bruger #1236 @ 08.09.03 20:16
min virker fint
User
Bruger #4612 @ 22.10.03 11:06
Hej
Jeg håber at det er det rette sted jeg henvender mig!
Jeg har et problem med en afstemningsboks jeg har fået fat i den er sat på side www.boykot-pia.dk
Jeg ønsker at man skal kunne stemme /sætte kryds på flere end en svar mulighed!
Kan det lade sig gøre ? Hvordan?

email: amir_pk@hotmail.com

Udskyld hvis det er det forkete sted!

På forhånd TAK
Amir
User
Bruger #3976 @ 06.11.03 14:32
Jeg leder efter din Pollbar ? hvor er den ?
User
Bruger #3976 @ 06.11.03 14:47
Og den der klik så kommer det hele frem hvor er den ?
VH
Tarsankode
User
Bruger #3976 @ 07.11.03 22:05
$kode .= "<td colspan="2"><div class="pollanswer">$a:</div></td>"; <-- det kan man ik

Den kan jeg ikke få til at virke ?
Vh
Tarsankode
User
Bruger #3884 @ 21.11.03 15:32
Tarsankode:
$kode .= "<td colspan="2"><div class="pollanswer">$a:</div></td>";
eller
$kode .= '<td colspan="2"><div class="pollanswer">$a:</div></td>';
User
Bruger #4428 @ 27.11.03 19:32
zyxrp, kan få alt til at virke (hehe) *GG*
User
Bruger #3763 @ 09.03.04 18:34
jeg har ikke prøvat det med databaser før så jeg forstod ikke helt det med at laven en !!
User
Bruger #6783 @ 08.12.04 23:31
får hele tiden en fejl:
Parse error: parse error in /usr/home/whitehat_dk/users/mikkel87/mikkel/skabeloner/pollfunctions.php on line 38
User
Bruger #6366 @ 01.01.05 21:17
God artikel, det hele virker :)
User
Bruger #7826 @ 03.07.05 13:14
God artikel, fik nogle små fejl, men dem kan man jo selv rette når de kommer :) men jeg vil gerne hvis der er nogle som kan hjælpe mig med at få den til at vise stemmerne som graf og ikke %tal :S
User
Bruger #8025 @ 24.08.05 20:35
God og fin artikel. Kan ikke få den helt til at virke. Men prøver stadig. Der er lidt fejl, men det er til at klare. Jeg har en fejl, jeg ikke kan rette. Det er denne:

Fatal error: Call to undefined function: havevoted() in /web/www/frac/users/p0ulsen/index.php on line 14

.. Hvad betyder det ?

Min linje 14 ser sådan ud:

if(HaveVoted($pid) != true) {

Med venlig hilsen Jesper Poulsen
http://p0ulsen.frac.dk
User
Bruger #8025 @ 27.08.05 15:22
Nogen som kan få STEM knappen frem ? Hvordan?!
User
Bruger #7041 @ 05.07.06 21:58
4 stjerner til artiklen her fra. Det er et virkelig brugbart og smart script du har strikket sammen og det kan nemt udvides hvis man ønsker det. Den 5. stjerne ryger dog fordi jeg synes det er meget misvisende at kalde niveauet for nybegynder. Der skal lidt erfaring til for at man kommer igennem og får det til at virke og mange kunne godt forledes til at tro det bare er et copy'n'paste script, det er det ikke (hvilket er 100% iorden da det jo ikke er forbudt at tænke selv) og det synes jeg lige du bør gøre klart opmærksomt på :)


Til folk der har problemer, så er der hjælp at hente i denne tråd: http://udvikleren.dk/Thread.aspx?f=6&t=17079&tech=6

Jonas
User
Bruger #15398 @ 21.10.09 14:34
Hej
Det er lige det jeg er ude efter, men jeg har et problem, med denne poll, som jeg ikke lige kan gennemskue selv.

Jeg får denne fejl :
Parse error: syntax error, unexpected T_STRING in /home/virtual/mitdomæne.nu/public_html/poll2/pollfunctions.php on line 40

og line 40 se sådan ud:
$kode .= "<div class="pollquestion">$q</div>";


Hvor gå det galt henne ?

mvh NUls
Du skal være logget ind for at skrive en kommentar.
t