Polls zijn tegenwoordig bijna overal op het web en er zijn tal van services die u een drop-in polling bieden. Maar wat als u er zelf een wilt schrijven? Deze tutorial neemt je mee door de stappen om een eenvoudige PHP-gebaseerde poll te maken, inclusief database-instellingen, stemverwerking en het weergeven van de poll.
Om enquêteresultaten op te slaan, gaan we drie stukjes informatie opslaan:
Voor deze zelfstudie gebruiken we PDO en SQLite. Als u met SQLite3 werkt, kunt u een nieuwe database maken via het opdrachtregelhulpprogramma; als u een oudere versie gebruikt, heeft een snel PHP-script de juiste oplossing. Dit is degene die voor deze tutorial is gebruikt:
setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ dbh-> exec ('CREATE TABLE tally (QID varchar (32) NOT NULL, AID integer NOT NULL, stemmen integer NOT NULL, PRIMARY KEY (QID, AID))'); catch (PDOException $ e) echo "ERROR !!: $ e"; Uitgang; echo "db met succes aangemaakt."; ?>
Met dit eenvoudige script wordt een SQLite-database gemaakt in de directory waarin u het uitvoert. In tegenstelling tot mySQL is de database hier een plat bestand. Als u bekend bent met SQL, de creëren
zou voor u logisch moeten zijn, hoewel de laatste regel voor sommige mensen misschien nieuw is:
PRIMAIRE SLEUTEL (QID, HULP)
Dit creëert een samengestelde sleutel voor de database. Inzendingen in beide kolommen hoeven niet uniek te zijn voor die kolom, maar de combinatie van beide moet uniek zijn.
Voordat u begint met het schrijven van een PHP, moet u beslissen hoe u uw poll in termen van markup maakt. We gaan proberen de opmaak zo semantisch en eenvoudig mogelijk te houden. Je poll zal twee looks hebben:
Bij het schrijven van deze HTML worden enkele klassen opgenomen om later met de CSS te helpen.
Omdat een peiling vooral een lijst met antwoorden is, gaan we een ongeordende lijst opnemen om die antwoorden te bevatten. Voor de vraag zelf gaan we een heading-tag gebruiken.
Dat is vrij eenvoudig, maar bevat geen formulierelementen. Keuzerondjes zijn het meest geschikt, omdat we maar één antwoord per peiling toestaan. We gaan ook de labeltag gebruiken om antwoorden te koppelen aan het juiste keuzerondje. Nu lijkt ons formulier-HTML er meer op:
Dat is een beetje ingewikkelder, maar niet slecht. Nog steeds een beetje meer toe te voegen. We gaan een veldset-tag toevoegen om een aantal stylingopties te openen, en natuurlijk hebben we een knop Verzenden nodig!
Voor elk antwoord wordt een nieuwe LI-tag toegevoegd en de waarde van het keuzerondje verhoogd. Dat zal uiteindelijk worden gedaan door onze PHP. De extra HTML is de veldset-tag en de alinea rond de knop - beide worden gebruikt door onze CSS.
De HTML zal bijna identiek zijn voor de antwoordweergave. De regelitemtags bevatten geen formulierelement en we voegen een div toe die kan worden gebruikt om het percentage van de ontvangen stemmen aan te geven. Hier ziet u hoe dat eruit zal zien:
Ja, dat is een inline-stijl die u daar ziet. Die stijl wordt gegenereerd door onze PHP op basis van het huidige percentage van elk individueel antwoord. Dit is wat we tot nu toe hebben:
De HTML die we in de laatste stap hebben gemaakt, was niet erg aantrekkelijk. Laten we kijken of we dat een beetje kunnen oplossen. We gaan de prachtige CSS3 PIE-bibliotheek (progressive Internet Explorer) gebruiken, zodat we een vergelijkbare blik kunnen krijgen in alle browsers. Om deze bibliotheek goed te laten werken, zijn er talloze gevallen waarin u een relatieve positie op elementen moet toepassen. U kunt alle details op de bibliotheekwebsite lezen.
We gaan de formuletag gebruiken als onze container. Het heeft mooie, afgeronde hoeken en een beetje een slagschaduw. De onderstaande stijlen specificeren ook een breedte en opvulling.
form.webPoll background: #ededed; gedrag: url (PIE.php); border: 1px solid #bebebe; -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; -moz-box-shadow: # 666 0 2px 3px; -webkit-box-shadow: # 666 0 2px 3px; box-shadow: # 666 0 2px 3px; marge: 10px 0 10px 8px; padding: 6px; position: relative; width: 246px;
De belangrijkste regel hier is het gedragsattribuut. Dit wordt genegeerd door niet-IE-browsers en voegt de CSS3-functionaliteit toe aan IE6-8.
Nog steeds lelijk, maar een merkbare verbetering.
Vervolgens gaan we een leuk kader rond de antwoorden maken en een beetje illusie gebruiken om de rand er als één pixel in te laten lijken. Dit wordt gedaan door de buitenste rand (de veldset) dezelfde kleur te geven als de binnenkant en vervolgens de ongeordende tag te gebruiken als onze echte rand. Dit is de CSS:
form.webPoll-veldset background: #FCFAFC; gedrag: url (PIE.php); border: 1px solid #FCFAFC; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; margin: 0; padding: 0; position: relative; form.webPoll ul behaviour: url (PIE.php); rand: 2px #bebebe vast; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; font-family: Verdana; font-size: 10px; list-style-type: none; margin: 0; opvulling: 10px 0; position: relative;
Vervolgens moeten we een beetje CSS toevoegen om onze opties er beter uit te laten zien.
form.webPoll li margin: 0 16px; overflow: auto; opvulling: 4px 0 6px; positie: relatief; form.webPoll input position: absolute; top: 4px; * top: 0; links: 0; marge: 0; padding: 0; label.poll_active float: right; width: 90%;
U vraagt zich misschien af waarom we absolute positionering op de ingangen gebruiken en het label zwevend maken. De reden is simpel: antwoorden op meerdere regels. Als een antwoord op uw poll-vraag lang is, wilt u dat het keuzerondje eruitziet als een opsommingsteken in een niet-geordende lijst. Hierdoor blijft de tekst eromheen als het meerdere regels zijn.
Er is ook een stijl die specifiek op IE is gericht met de * hack om ervoor te zorgen dat de knoppen correct worden uitgelijnd in IE6-8.
We moeten ook de balk die wordt gebruikt om resultaten weer te geven, opmaken. We voegen dat nu toe:
form.webPoll .result background: # d81b21; achtergrond: -webkit-gradiënt (lineair, linker boven, links onder, van (# ff8080), tot (# aa1317)); achtergrond: -moz-linear-gradient (bovenaan, # ff8080, # aa1317); -pie-achtergrond: lineair verloop (# ff8080, # aa1317); rand: 1px rode vaste stof; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; beiden opschonen; kleur: #efefef; padding-left: 2px; gedrag: url ('PIE.php');
Er is nog een ander attribuut hier: -pie-background, wat ons in staat stelt om, in samenwerking met de PIE-bibliotheek, gradient-achtergronden te gebruiken in IE. Er zijn nog een paar aanrakingen om toe te voegen.
Een standaard H4 is misschien niet wat je zoekt, dus laten we daar wat styling aan toevoegen.
form.webPoll h4 color: # 444; font-family: Georgia, serif; font-size: 19px; font-weight: 400; line-height: 1.4em; marge: 6px 4px 12px; padding: 0;
En ik ben geen grote fan van standaardknoppen, dus we gaan een CSS-sprite gebruiken om het een beetje op te fleuren.
.knoppen marge: 8px 0 1px; padding: 0; text-align: right; width: 122px; .vote background: url (res / vote.png) herhaal scroll 0 0 transparant; grens: medium geen; hoogte: 40px; text-indent: -9999em; width: 122px; .stem: hover background-position: 0 -41px; cursor: wijzer;
Hoe zit het met IE6? Het ondersteunt de hover psudo-klasse niet! We kunnen deze gebruikers in de kou laten staan (ze zien nog steeds de standaardstatus van de knop) of we kunnen een andere mooie kleine GPL-bibliotheek met licentie gebruiken, Whatever: hover.
Om sommige IE6 eigenaardigheden te herbergen, moeten bepaalde elementen iets hebben dat "HasLayout" heet. De eenvoudigste manier om dit te doen, is door een eigenschap van de zoomfunctie in te stellen voor deze elementen. De eigenschap wordt genegeerd door niet-IE-browsers.
form.webPoll ul, li / * // Maak IE6 blij // * / zoom: 1;
Je zult ook merken dat er grenzen zijn tussen elke vraag. Dit is gedaan met een extra klasse op de LI-tags die een rand specificeren. De klasse wordt toegewezen aan alle behalve het laatste item door het PHP-script.
Het voltooide CSS-bestand bevindt zich in de download.
Nu is het tijd om de PHP te maken om polls te genereren, resultaten te tonen en stemmen af te handelen. Ik wil het script graag zo eenvoudig mogelijk blijven gebruiken, dus ik ben van plan het gebruik van tevoren te plannen. Als u een peiling op een bepaalde plaats op een pagina wilt maken, gebruikt u gewoon de volgende PHP:
$ a = nieuwe webPoll (array ('Over welke onderwerpen zou u meer willen weten?', 'HTML & CSS', 'JavaScript', 'JS Frameworks (jQuery, etc.)', 'Ruby / Ruby on Rails', ' PHP ',' mySQL '));
Dat is het. U geeft een array door aan de constructor die de vraag bevat, gevolgd door de antwoorden. Om de vragen in de database bij te houden, maken we een MD5-hash van de vraag die als ID moet worden gebruikt.
Er zijn bepaalde gegevens die nodig zijn voor elke poll; we gaan een deel daarvan opslaan in klassenobjecten. We moeten de vraag en de antwoorden opslaan, de eenvoudige HTML, de vraag-ID en enige informatie over het tekenen van de resultatenbalken. Dit is het begin:
class webPoll # maakt sommige dingen leesbaarder later const POLL = true; const VOTES = false; # aantal pixels voor 1% op display bars public $ scale = 2; # de poll zelf openbaar $ question = "; public $ answers = array (); # de HTML private $ header = '\ n "; private $ button = ''; # vraag-ID private $ md5 = ";
De beginconstanten worden gebruikt in een van de methoden om het leesbaarder te maken, zodat het gemakkelijker is om te weten wat er aan de hand is.
Let op de verborgen invoer die hier is toegevoegd. Dit is de vraagidentificatie die wordt gebruikt om informatie in de database op te slaan. Alle waarden in de HTML die worden omringd door procenttekens, worden vervangen.
Omdat het al is besloten, zal de poll worden gemaakt door een object te maken. Laten we de methode __construct bekijken.
publieke functie __construct ($ params) $ this-> question = array_shift ($ params); $ this-> answers = $ params; $ this-> md5 = md5 ($ this-> vraag); $ this-> header = str_replace ('% src%', $ _SERVER ['SCRIPT_NAME'], $ this-> header); $ this-> header = str_replace ('% qid%', $ this-> md5, $ this-> header); $ this-> header = str_replace ('% question%', $ this-> question, $ this-> header); # heeft de gebruiker al gestemd? isset ($ _ COOKIE [$ this-> md5])? $ this-> poll (self :: VOTES): $ this-> poll (self :: POLL);
In de eerste regel pellen we de vraag van de array-stack met array_shift en slaan we deze op in een property. We slaan ook de vragen op en laten ze als een array achter. We maken hier ook de vraagidentificatie, door een md5-hash van de vraag zelf te maken.
De volgende drie regels voeren enkele vervangingen uit op de HTML. De eerste stelt onze formulieractie in om te wijzen naar de pagina waarop de poll een is. De tweede plaatst onze vraag-ID in een veld met een verborgen formulier. De derde plaatst onze vraag in de HTML.
In de laatste regel van de constructor controleren we of de gebruiker heeft gestemd over deze specifieke peiling en als hij dat heeft, laten we de stemmen zien. Als hij dat niet heeft gedaan, laten we de peiling zien.
Beide genereren de peiling en het genereren van de resultaten zijn zeer vergelijkbare operaties. Om onze code DROOG te houden, doorbreken we de creatie in drie methoden. De belangrijkste is "poll".
enquête voor persoonlijke functies ($ show_poll) $ replace = $ show_poll? $ this-> knop: "; $ this-> footer = str_replace ('% button%', $ replace, $ this-> footer); # static function heeft geen toegang tot instantievariabele if (! $ show_poll) $ results = webPoll :: getData ($ this-> md5); $ votes = array_sum ($ results); for ($ x = 0; $ xantwoorden); $ x ++) $ this-> center. = $ show_poll? $ this-> pollLine ($ x): $ this-> voteLine ($ this-> antwoorden [$ x], $ resultaten [$ x], $ stemmen); echo $ this-> header, $ this-> center, $ this-> footer;
Dit is het overzicht van wat er in deze functie gebeurt:
regel 2 en 3: We hebben alleen een stemknop nodig als de gebruiker niet heeft gestemd. Hier bepalen we of we de knop HTML gebruiken of niet, en vervolgens de HTML invoegen, of de% -knop% placeholder vervangen door een lege tekenreeks.
regel 6 - 8: Als we de peiling niet laten zien, hebben we duidelijk de resultaten nodig, dus hier gaan we ze ophalen. We berekenen ook het totale aantal uitgebrachte stemmen voor later gebruik bij het bepalen van de percentages.
regels 11 - 12: Dit genereert de LI-tags in onze HTML. Afhankelijk van het feit of we de peiling of de resultaten weergeven, genereren we verschillende HTML. Deze HTML-generatie wordt overgezet naar twee functies:
regel 15: Dumpt de gegevens eenvoudigweg naar de pagina.
Dit is een zeer eenvoudige methode, die de huidige index van het antwoord als argument gebruikt.
persoonlijke functie pollLine ($ x) isset ($ this-> antwoorden [$ x + 1])? $ class = 'bordered': $ class = "; return"
Er wordt gecontroleerd of er een antwoord is na de huidige op de eerste regel en als er een antwoord is, wordt een klasse van grenzen toegepast op die LI-tag. Het allerlaatste antwoord krijgt deze klasse niet, waardoor we het beoogde visuele effect kunnen bereiken.
Bij deze methode worden er 3 parameters doorgegeven:
Met die informatie kunnen de LI-tags voor de stemresultaten worden geproduceerd.
persoonlijke functie stemLine ($ antwoord, $ resultaat, $ stemmen) $ resultaat = isset ($ resultaat)? $ resultaat: 0; $ procent = rond (($ resultaat / $ stemmen) * 100); $ width = $ percent * $ this-> schaal; terug "
Aangezien het mogelijk is dat er geen stemmen op een optie staan, blijft het resultaat $ ongemoeid. Als we dit detecteren, geven we het een standaardwaarde van 0 stemmen.
Vervolgens bepalen we welk percentage van de stemmen de optie heeft en gebruiken we uiteindelijk de schaaleigenschap om de breedte in pixels te bepalen die de resultatenbalk zou moeten zijn. Dan retourneren we uiteindelijk de HTML die al die informatie bevat.
Als u een beetje omhoog kijkt, ziet u dat we de methode getData () gebruiken die is gedefinieerd als een statische methode in de klas. Waarom statisch? Omdat als we besluiten deze poll later te verbeteren door deze op AJAX gebaseerd te maken, we toegang tot die methode willen zonder object te maken. Dit is de methode:
statische functie getData ($ question_id) try $ dbh = nieuwe PDO ('sqlite: voting.db'); $ dbh-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ STH = $ dbh-> prepare ('SELECT AID, voting FROM tally WHIG QID =?'); $ STH-> execute (array ($ question_id)); catch (PDOException $ e) # Fout bij ophalen van gegevens, stuur lege return set array (0); while ($ row = $ STH-> fetch ()) $ results [$ row ['AID']] = $ row ['stemmen']; return $ resultaten;
De vraag-ID wordt in de methode doorgegeven en er wordt een array geretourneerd met daarin de antwoord-ID's en het aantal stemmen dat het antwoord heeft. Als een antwoord geen stemmen heeft, heeft het geen invoer in de array, die we al behandeld hebben in de methode voteLine ().
Omdat databasefouten in web polls bijzonder tragisch zijn, gaan we eenvoudigweg een lege array retourneren als er een optreedt. De gebruiker krijgt 0 stemmen voor elk resultaat. In een productieomgeving wilt u deze fout mogelijk registreren in een bestand of de beheerder een e-mail sturen.
We gaan een tweede statische methode aan de klas toevoegen en deze zal inkomende stemmen verwerken. Stemmen worden alleen geteld als de gebruiker niet eerder heeft gestemd (zoals bepaald door een cookie) en zodra de gebruiker heeft gestemd, zullen we een cookie instellen die dit aangeeft.
In dit soort webapplicaties is het bijna onmogelijk om meerdere stemmen te stoppen zonder sommige legitieme gebruikers uit te sluiten. Een cookie instellen is slechts een basisvoorzorgsmaatregel.
Dit is een van de meer complexe methoden in onze webPoll-klasse, en we gaan er in drie delen naar kijken.
statische functie vote () if (! isset ($ _ POST ['QID']) ||! isset ($ _ POST ['AID']) || isset ($ _ COOKIE [$ _ POST ['QID']])) terug te keren;
Een aanroep van de methode vote () staat bovenaan onze PHP-pagina, dus het eerste wat we willen doen, is beslissen of er een stemming moet worden verwerkt of niet. De bovenstaande verklaring is hoe we dit bepalen. Hier is wat het zegt:
Als een van deze waar is, hoeven we geen stem te verwerken en verlaten we de methode.
$ dbh = nieuwe BOB ('sqlite: voting.db'); $ dbh-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); probeer $ sth = $ dbh-> prepare ("INSERT INTO tally (QID, AID, votes) waarden (: QID,: AID, 1)"); $ Sth-> execute (array ($ _ POST [ 'QID'], $ _ POST [ 'AID'])); catch (PDOException $ e) # 23000 foutcode betekent dat de sleutel al bestaat, dus UPDATE! if ($ e-> getCode () == 23000) try $ sth = $ dbh-> prepare ("UPDATE-telling SET-stemmen = stemmen + 1 WAAR QID =: QID AND AID =: AID"); $ Sth-> execute (array ($ _ POST [ 'QID'], $ _ POST [ 'AID'])); catch (PDOException $ e) $ this-> db_error ($ e-> getMessage ()); else $ this-> db_error ($ e-> getMessage ());
Dit ziet er veel ingewikkelder uit dan het werkelijk is. Wat hier gebeurt, is dat we controleren of een bepaald antwoord eerder een stem heeft gekregen. Als dat niet het geval is, maken we een nieuw record voor dat antwoord en geven we er één stem. Als dit het geval is, werken we het bestaande record bij. Dus hoe is het beslissen wat te doen?
Uitzondering magie met BOB.
Weet je nog aan het begin dat we onze primaire sleutel met meerdere kolommen hebben gemaakt? Wanneer we proberen een record in de tabel in te voegen die overeenkomt met een bestaand QID / AID-paar, wordt er een uitzondering gegenereerd en in het bijzonder is de uitzonderingscode 23000 (dubbele sleutel).
Als het invoegsel een uitzondering genereert, controleren we de uitzonderingscode en als deze overeenkomt met 23000, proberen we de record bij te werken. Natuurlijk, als de invoeging mislukt om een andere reden, of als de update ook mislukt, zullen we gewoon een oproep doen naar een methode met de naam db_error () die gewoon een generiek foutbericht echoot. Net als eerder zou een productieomgeving deze fout registreren en / of de beheerder op de hoogte stellen.
Eindelijk, het einde van de methode:
# invoer in $ _COOKIE om aan te geven dat de gebruiker gestemd heeft, als hij dat heeft ($ sth-> rowCount () == 1) setcookie ($ _ POST ['QID'], 1, time () + 60 * 60 * 24 * 365); $ _COOKIE [$ _ POST ['QID']] = 1;
Door rowCount () te gebruiken, kunnen we verifiëren of we een stemming hebben bijgewerkt of ingevoegd. Als een stem met succes is geregistreerd, stellen we een cookie in die evenveel aangeeft, waarbij de vraag-ID als de cookienaam wordt gebruikt.
Naast het instellen van de cookie vullen we de super-globale $ _COOKIE in, dus wanneer de peiling wordt weergegeven, worden antwoorden weergegeven in plaats van de peiling opnieuw te presenteren.
We hebben de PHP geschreven, de CSS en HTML ingesteld, nu is het tijd om alles in gebruik te nemen. In dit voorbeeld laten we alles gewoon achter op een pagina die anders leeg is. Plaats helemaal bovenaan de pagina het volgende:
Het is belangrijk dat dit de absolute top van de pagina is, vóór elke HTML. Waarom? Want als er een stemming is om te verwerken, kan er een cookie worden geschreven en kunt u geen cookies schrijven nadat al het andere is verzonden. De aanroep van de statische methode vote () retourneert als er niet de juiste POST-gegevens zijn om te verwerken.
Vervolgens nemen we alle stijlen op die we als een afzonderlijke stylesheet hebben geschreven. We zullen ook een specifieke stijl toevoegen alleen voor IE die eerder werd genoemd om de: hover psudo-class in te schakelen.
In de BODY van je HTML-pagina, drop je in de volgende PHP om de polls in te voegen:
$ a = nieuwe webPoll (array ('Over welke onderwerpen zou u meer willen weten?', 'HTML & CSS', 'JavaScript', 'JS Frameworks (jQuery, etc.)', 'Ruby / Ruby on Rails', ' PHP ',' mySQL ')); $ b = nieuwe webPoll (array ('Wat is uw vraag?', 'Geen vraag', 'Waarom?', 'Wanneer?', 'Waar?'));
Dat is het! Bedankt voor het lezen. Alle gedachten, vragen of suggesties?