Créer un sondage Web avec PHP

Les sondages sont presque omniprésents sur le Web aujourd'hui, et de nombreux services vous fourniront un sondage sans rendez-vous. Mais si vous voulez en écrire un vous-même? Ce tutoriel vous guidera tout au long de la création d'un sondage simple basé sur PHP, comprenant la configuration de la base de données, le traitement des votes et l'affichage du sondage..


Étape 1: Planifiez et créez la base de données

Afin de stocker les résultats du sondage, nous allons stocker trois informations:

  • Un identifiant de question
  • Un identifiant de réponse
  • Le nombre de voix qu'une paire question / réponse a obtenu

Pour ce tutoriel, nous utiliserons PDO et SQLite. Si vous travaillez avec SQLite3, vous pouvez créer une nouvelle base de données via l'outil de ligne de commande. si vous utilisez une version plus ancienne, un script PHP rapide fera l'affaire. Voici celui utilisé pour ce tutoriel:

setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ dbh-> exec ('CREATE TABLE tally (QID varchar (32) NON NUL, AID entier NON NUL, votes entier NULL, PRIMARY KEY (QID, AID))');  catch (PDOException $ e) echo "ERREUR !!: $ e"; sortie;  echo "db créé avec succès."; ?>

Ce script simple créera une base de données SQLite dans le répertoire où vous l’exécutez. Contrairement à MySQL, la base de données est un fichier plat. Si vous connaissez SQL, le créer devrait avoir un sens pour vous, bien que la dernière ligne puisse être nouvelle pour certaines personnes:

CLÉ PRIMAIRE (QID, AID)

Cela crée un clé composite pour la base de données. Les entrées de l'une ou l'autre colonne ne doivent pas nécessairement être uniques à cette colonne, mais la combinaison des deux doit être unique..


Étape 2: Concevez le code HTML de votre sondage

Avant de commencer à écrire du PHP, vous devez décider comment créer votre sondage en termes de balisage. Nous allons essayer de garder le balisage aussi sémantique et simple que possible. Votre sondage aura deux regards:

  • Question en attente de réponse
  • Résultats actuels du sondage

En écrivant ce code HTML, certaines classes seront incluses pour aider ultérieurement avec le CSS.

Sondage

Comme un sondage est principalement une liste de réponses, nous allons incorporer une liste non ordonnée pour contenir ces réponses. Pour la question elle-même, nous allons utiliser une balise de titre.

Quelle question voudriez-vous poser?

  • Répondez ici
  • Une autre réponse ici

C'est assez basique, mais n'inclut aucun élément de formulaire. Les boutons radio sont les plus appropriés car nous n'autorisons qu'une réponse par sondage. Nous allons également utiliser l’étiquette pour associer les réponses au bon bouton radio. Maintenant, notre formulaire HTML ressemble plus à ceci:

Quelle question voudriez-vous poser?

C'est un peu plus complexe, mais pas trop mal. Encore un peu plus à ajouter. Nous allons inclure une balise fieldset pour ouvrir quelques options de style, et bien sûr nous avons besoin d'un bouton d'envoi!

Quelle question voudriez-vous poser?

Pour chaque réponse, une nouvelle balise LI est ajoutée et la valeur du bouton radio incrémentée. Cela sera éventuellement fait par notre PHP. Le code HTML supplémentaire correspond à la balise fieldset et au paragraphe placé autour du bouton, qui seront tous deux utilisés par notre CSS.

Répondre Voir

Le code HTML sera presque identique pour la vue des réponses. Les balises d'élément de ligne ne contiendront pas d'élément de formulaire et nous ajouterons un div pouvant être utilisé pour afficher le pourcentage de votes reçus. Voici à quoi cela ressemblera:

  • Oui, c'est un style en ligne que vous voyez là. Ce style sera généré par notre PHP en fonction du pourcentage actuel de chaque réponse. Voici ce que nous avons jusqu'à présent:


    Étape 3: stylisez le formulaire

    Le code HTML que nous avons créé à la dernière étape n’était pas très attrayant. Voyons si nous pouvons arranger ça un peu. Nous allons utiliser la magnifique bibliothèque CSS3 PIE (Internet Explorer progressif) afin d’obtenir une apparence similaire sur tous les navigateurs. Pour que cette bibliothèque fonctionne correctement, vous devez appliquer une position relative aux éléments dans de nombreux cas. Vous pouvez lire tous les détails sur le site de la bibliothèque.

    Style de la balise de formulaire

    Nous allons utiliser la balise de formulaire comme conteneur. Il y aura de beaux coins arrondis et un peu d'ombre portée. Les styles ci-dessous spécifient également une largeur et un rembourrage.

    form.webPoll background: #edededed; comportement: url (PIE.php); bordure: 1px solide #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; rembourrage: 6px; position: relative; largeur: 246px; 

    La ligne clé ici est l'attribut de comportement. Ceci sera ignoré par les navigateurs non-IE et ajoutera la fonctionnalité CSS3 à IE6-8..

    Toujours moche, mais une amélioration notable.

    Box the Answers

    Ensuite, nous allons créer un joli cadre autour des réponses et utiliser un peu d’illusion pour que la bordure paraisse incrustée d’un pixel. Pour ce faire, vous colorez la même couleur que l'intérieur, ainsi que la balise de liste non ordonnée, en tant que notre bordure réelle. Voici le CSS:

    form.webPoll fieldset background: #FCFAFC; comportement: url (PIE.php); bordure: 1px solide #FCFAFC; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; marge: 0; rembourrage: 0; position: relative;  form.webPoll ul behavior: url (PIE.php); bordure: 2px #bebebe solide; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; famille de polices: verdana; taille de police: 10px; type de style de liste: aucun; marge: 0; remplissage: 10px 0; position: relative; 

    Style les réponses

    Ensuite, nous devons ajouter un peu de CSS pour améliorer la présentation de nos options..

    form.webPoll li margin: 0 16px; débordement: auto; remplissage: 4px 0 6px; position: relative;  form.webPoll input position: absolute; en haut: 4 px; * en haut: 0; gauche: 0; marge: 0; rembourrage: 0;  label.poll_active float: right; largeur: 90%; 

    Vous vous demandez peut-être pourquoi nous utilisons un positionnement absolu sur les entrées et un libellé flottant. La raison est simple: réponses multi-lignes. Si la réponse à votre question de sondage est longue, vous souhaitez que le bouton radio apparaisse comme une puce sur une liste non ordonnée - en attente. Cela empêchera le texte de s'enrouler s'il est composé de plusieurs lignes..

    Il existe également un style ciblant spécifiquement IE avec le hack * pour que les boutons s'alignent correctement dans IE6-8..

    Nous devons également styler la barre utilisée pour afficher les résultats. Nous allons ajouter que maintenant:

    form.webPoll .result background: # d81b21; arrière-plan: -webkit-gradient (linéaire, gauche haut, bas gauche, de (# ff8080), à (# aa1317)); arrière-plan: -moz-linear-gradient (haut, # ff8080, # aa1317); -pie-background: gradient linéaire (# ff8080, # aa1317); bordure: 1px rouge solide; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; clarifier les deux; couleur: #EFEFEF; padding-left: 2px; comportement: url ('PIE.php'); 

    Il y a un autre nouvel attribut ici: -pie-background, qui nous permet, en conjonction avec la bibliothèque PIE, d'utiliser des arrière-plans dégradés dans IE. Il reste encore quelques petites touches à ajouter.

    Question et bouton

    Un H4 par défaut peut ne pas être ce que vous cherchez, ajoutons donc un style à celui-ci.

    form.webPoll h4 color: # 444; famille de polices: Georgia, serif; taille de police: 19px; poids de la police: 400; hauteur de ligne: 1.4em; marge: 6px 4px 12px; rembourrage: 0; 

    Et je ne suis pas un grand fan des boutons par défaut, nous allons donc utiliser un sprite CSS pour l’animer un peu.

    .boutons margin: 8px 0 1px; rembourrage: 0; text-align: right; largeur: 122px;  .vote background: url (res / vote.png) répéter le défilement 0 0 transparent; bordure: moyenne aucune; hauteur: 40px; retrait du texte: -9999em; largeur: 122px;  .vote: hover background-position: 0 -41px; curseur: pointeur; 

    Qu'en est-il d'IE6? Il ne supporte pas la psudo-classe en vol stationnaire! Nous pouvons soit laisser ces utilisateurs dehors dans le froid (ils verront toujours l'état par défaut du bouton) ou nous pouvons utiliser une autre jolie petite bibliothèque sous licence GPL, Whatever: hover.

    Derniers bits

    Afin de prendre en charge certaines bizarreries IE6, certains éléments doivent avoir un déclencheur appelé "HasLayout". Pour ce faire, la méthode la plus simple consiste à définir une propriété de zoom pour ces éléments. La propriété est ignorée par les navigateurs non-IE.

    form.webPoll ul, li / * // Rendre IE6 heureux // * / zoom: 1; 

    Vous remarquerez également qu'il y a des frontières entre chaque question. Cela a été fait avec une classe supplémentaire sur les balises LI spécifiant une bordure. La classe sera assignée à tous sauf le dernier élément par le script PHP.

    Le fichier CSS complété est contenu dans le téléchargement.


    Étape 4: Créer une classe PHP - Choisir l'interface

    Il est maintenant temps de créer PHP pour générer des sondages, afficher les résultats et gérer les votes. J'aimerais continuer à utiliser le script aussi simplement que possible. Je planifie donc son utilisation à l'avance. Pour créer un sondage à un endroit particulier d'une page, utilisez simplement le code PHP suivant:

    $ a = new webPoll (array ('Quels sujets souhaiteriez-vous en savoir plus?', 'HTML & CSS', 'JavaScript', 'JS Frameworks (jQuery, etc)', 'Ruby / Ruby on Rails', ' PHP ',' MySQL '));

    C'est tout. Vous passerez un tableau au constructeur contenant la question suivie des réponses. Afin de suivre les questions dans la base de données, nous allons créer un hachage MD5 de la question à utiliser comme identifiant.


    Étape 5: Choisir les propriétés de la classe

    Il y a certaines données dont chaque sondage aura besoin; nous allons stocker certaines de ces propriétés dans la classe. Nous devrons stocker la question et les réponses, le code HTML de base, l'identificateur de la question et des informations sur la manière de dessiner les barres de résultats. Voici le début:

    La classe webPoll # rend certaines choses plus lisibles plus tard const POLL = true; const VOTES = false; # nombre de pixels pour 1% sur les barres d’affichage public $ scale = 2; # le sondage lui-même public $ question = "; public $ answers = array (); # le HTML privé $ header = '

    %question%

      '; private $ center = "; private $ footer =" \ n
    % bouton% \ n
    \ n "; private $ button = '

    '; # identifiant de question private $ md5 = ";

    Les constantes initiales seront utilisées dans l’une des méthodes pour la rendre plus lisible afin qu’il soit plus facile de savoir ce qui se passe..

    Prenez note de l'entrée cachée qui a été ajoutée ici. C'est l'identifiant de la question utilisé pour stocker les informations dans la base de données. Toutes les valeurs du code HTML entourées de signes de pourcentage seront remplacées.


    Étape 6: Créez le sondage HTML ou les réponses

    Comme il a déjà été décidé que le sondage sera fait en créant un objet, examinons la méthode __construct.

    fonction publique __construct ($ params) $ this-> question = array_shift ($ params); $ this-> réponses = $ params; $ this-> md5 = md5 ($ this-> question); $ this-> header = str_replace ('% src%', $ _SERVER ['SCRIPT_NAME'], $ this-> en-tête); $ this-> header = str_replace ('% qid%', $ this-> md5, $ this-> en-tête); $ this-> header = str_replace ('% question%', $ this-> question, $ this-> en-tête); # l'utilisateur a-t-il déjà voté? isset ($ _ COOKIE [$ this-> md5])? $ this-> sondage (auto :: VOTES): $ this-> sondage (auto :: POLL); 

    Dans la première ligne, nous retirons la question de la pile de tableaux avec array_shift et la stockons dans une propriété. Nous stockons également les questions, les laissant comme un tableau. Nous créons également ici l'identifiant de la question, en créant un hachage md5 de la question elle-même..

    Les trois lignes suivantes effectuent des remplacements sur le code HTML. Le premier définit notre action de formulaire de manière à pointer vers la page où le sondage est un. La seconde place notre identifiant de question dans un champ de formulaire caché. Le troisième met notre question dans le HTML.

    Dans la dernière ligne du constructeur, nous vérifions si l'utilisateur a voté pour ce sondage, et s'il le fait, nous affichons les votes. S'il n'a pas, nous montrons le sondage.


    Étape 7: générer le sondage

    Générer le sondage et générer les résultats sont des opérations très similaires. Afin de garder notre code DRY, nous divisons la création en trois méthodes. Le principal est "sondage".

    fonction privée poll ($ show_poll) $ replace = $ show_poll? $ this-> button: "; $ this-> footer = str_replace ('% button%', $ remplacer, $ this-> footer); # la fonction statique n'a pas accès à la variable d'instance if (! $ show_poll)  $ résultats = webPoll :: getData ($ this-> md5); $ votes = array_sum ($ results); pour ($ x = 0; $ xréponses); $ x ++) $ this-> center. = $ show_poll? $ this-> pollLine ($ x): $ this-> voteLine ($ this-> répond [$ x], $ résultats [$ x], $ votes);  echo $ this-> en-tête, $ this-> center, $ this-> footer; 

    Voici la ventilation de ce qui se passe dans cette fonction:

    lignes 2 et 3: Nous n'avons besoin d'un bouton de vote que si l'utilisateur n'a pas voté. Ici, nous déterminons si nous allons utiliser le bouton HTML ou non, puis insérer le code HTML ou remplacer le paramètre fictif du bouton% par une chaîne vide..

    lignes 6 - 8: Si nous ne diffusons pas le sondage, nous avons évidemment besoin des résultats, alors nous allons les chercher. Nous calculons également le total des votes exprimés pour une utilisation ultérieure dans la détermination des pourcentages..

    lignes 11 - 12: Cela génère les balises LI dans notre code HTML. Selon que nous affichons le sondage ou les résultats, nous générons un code HTML différent. Cette génération HTML est transférée à deux fonctions:

    • pollLine
    • ligne de vote

    ligne 15: Il suffit de transférer les données vers la page.


    Étape 8: La méthode pollLine ()

    C'est une méthode très simple, qui prend comme argument l'argument actuel de la réponse.

    fonction privée pollLine ($ x) isset ($ this-> répond [$ x + 1])? $ class = 'bordé': $ class = "; return" 
  • ";

    Il vérifie s'il existe une réponse après la réponse courante sur sa première ligne et, le cas échéant, applique une classe de bordures à cette balise LI. La toute dernière réponse n'obtiendra pas ce cours, ce qui nous permettra d'obtenir l'effet visuel voulu.


    Étape 9: La méthode voteLine ()

    Cette méthode reçoit 3 paramètres passés:

    • $ answer: La réponse à la question pour cette ligne
    • $ result: Le nombre de votes obtenus par cette option
    • $ votes: le nombre total de votes exprimés dans ce sondage

    Avec cette information, les étiquettes LI pour les résultats de vote peuvent être produites.

    fonction privée voteLine ($ answer, $ result, $ votes) $ result = isset ($ result)? $ résultat: 0; $ percent = round (($ result / $ votes) * 100); $ width = $ percent * $ this-> scale; revenir " 
  • $ percent%
  • ";

    Puisqu'il est possible qu'il n'y ait pas de vote pour une option, cela laissera effectivement $ result non défini. Si nous détectons cela, nous lui donnerons une valeur par défaut de 0 voix..

    Ensuite, nous déterminons le pourcentage de votes obtenus par l'option et nous utilisons enfin la propriété scale pour déterminer la largeur, en pixels, de la barre de résultats. Ensuite, nous renvoyons le code HTML contenant toutes ces informations..


    Étape 10: écrivez la méthode getData ()

    Si vous regardez un peu en arrière, vous verrez que nous appelons la méthode getData () qui est définie en tant que méthode statique dans la classe. Pourquoi statique? Parce que si nous décidons d'améliorer ultérieurement ce sondage en le rendant basé sur AJAX, nous voudrons avoir accès à cette méthode sans création d'objet. Voici la méthode:

    fonction statique getData ($ question_id) try $ dbh = new PDO ('sqlite :oting.db'); $ dbh-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); $ STH = $ dbh-> prepare ('SELECT AID, vote DE tally WHERE QERE =?'); $ STH-> execute (array ($ question_id));  catch (PDOException $ e) # Erreur lors de l’obtention des données, il suffit d’envoyer un ensemble de données vide return array (0);  while ($ row = $ STH-> fetch ()) $ results [$ row ['AID']] = $ row ['votes'];  retourne $ résultats; 

    L'ID de la question est passé à la méthode et il retournera un tableau contenant l'ID de la réponse et le nombre de votes de la réponse. Si une réponse n'a pas de vote, elle n'aura pas d'entrée dans le tableau, ce que nous avons déjà traité dans la méthode voteLine ().

    Les erreurs de base de données dans les sondages Web étant particulièrement tragiques, nous allons simplement renvoyer un tableau vide, le cas échéant. L'utilisateur obtiendra 0 voix pour chaque résultat. Dans un environnement de production, vous pouvez enregistrer cette erreur dans un fichier ou envoyer un courrier électronique à l'administrateur..


    Étape 11: Gérer un vote

    Nous allons ajouter une deuxième méthode statique à la classe et celle-ci gérera les votes entrants. Les votes ne seront comptés que si l'utilisateur n'a pas voté auparavant (comme déterminé par un cookie) et une fois que l'utilisateur a voté, nous définissons un cookie l'indiquant..

    Dans ce type d'application Web, il est presque impossible d'arrêter plusieurs votes sans exclure certains utilisateurs légitimes. L'installation d'un cookie n'est qu'une précaution de base.

    C'est l'une des méthodes les plus complexes de notre classe webPoll et nous allons l'examiner en trois parties..

    fonction statique vote () if (! isset ($ _ POST ['QID']) ||! isset ($ _ POST ['AID']) || isset ($ _ COOKIE [$ _ POST ['QID']])))  revenir; 

    Un appel à la méthode vote () sera en haut de notre page PHP, donc la première chose à faire est de décider s'il y a un vote à traiter ou non. La déclaration ci-dessus est la façon dont nous déterminons cela. Voici ce qu'il dit:

    • S'il n'y a pas d'identifiant de question dans nos données POST (OU !!)
    • S'il n'y a pas d'identificateur de réponse dans nos données POST (OU !!)
    • Si un cookie a déjà été défini avec l'identifiant de la question

    Si certaines d'entre elles sont vraies, nous n'avons pas à traiter de vote et nous laissons la méthode.

    $ dbh = new PDO ('sqlite :oting.db'); $ dbh-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION); try $ sth = $ dbh-> prepare ("INSERT INTO totaliser (QID, AID, votes) valeurs (: QID,: AID, 1)"); $ sth-> execute (array ($ _ POST ['QID'], $ _ POST ['AID']));  catch (PDOException $ e) code d'erreur # 23000 signifie que la clé existe déjà, alors UPDATE! if ($ e-> getCode () == 23000) try $ sth = $ dbh-> prepare ("UPDATE tally SET votes = votes + 1 WHERE QID =: QID ET AID =: AID"); $ sth-> execute (array ($ _ POST ['QID'], $ _ POST ['AID']));  catch (PDOException $ e) $ this-> db_error ($ e-> getMessage ());  else $ this-> db_error ($ e-> getMessage ()); 

    Cela a l'air beaucoup plus compliqué que ce n'est vraiment. Ce qui se passe ici, c'est que nous vérifions si une réponse particulière a déjà été votée. Si ce n'est pas le cas, nous créons un nouveau record pour cette réponse et lui donnons un vote. Si c'est le cas, nous mettons à jour l'enregistrement existant. Alors, comment décide-t-on quoi faire??

    Magie d'exception AOP.

    Rappelez-vous qu'au tout début nous avons créé notre clé primaire multi-colonnes? Lorsque nous essayons d'insérer dans la table un enregistrement qui correspond à une paire QID / AID existante, une exception est levée, et en particulier le code d'exception est 23000 (clé dupliquée)..

    Si l'insertion génère une exception, nous allons vérifier le code de l'exception. S'il correspond à 23000, nous essayerons plutôt de mettre à jour l'enregistrement. Bien sûr, si l'insertion échoue pour une raison différente, ou si la mise à jour échoue également, nous allons simplement appeler un procédé appelé db_error (), qui renvoie simplement un message d'erreur générique. Comme auparavant, un environnement de production consignera cette erreur et / ou notifiera l'administrateur.

    Enfin, la fin de la méthode:

     # entrée dans $ _COOKIE pour indiquer que l'utilisateur a voté, s'il a si ($ sth-> rowCount () == 1) setcookie ($ _ POST ['QID'], 1, time () + 60 * 60 * 24 * 365); $ _COOKIE [$ _ POST ['QID']] = 1; 

    En utilisant rowCount (), nous pouvons vérifier que nous avons mis à jour ou inséré un vote. Si un vote a été enregistré avec succès, nous définissons un cookie indiquant le même nombre, en utilisant l'identifiant de la question comme nom du cookie..

    En plus de définir le cookie, nous peuplons le super-global $ _COOKIE. Ainsi, lorsque le sondage est affiché, il affiche les réponses plutôt que de le présenter à nouveau..


    Étape 12: Mettez tout en action

    Nous avons écrit le PHP, mis en place le CSS et le HTML, il est maintenant temps de tout utiliser. Dans cet exemple, nous allons simplement tout déposer dans une page qui serait autrement vierge. Tout en haut de la page, insérez ce qui suit:

    Il est important que ce soit tout en haut de la page, avant tout HTML. Pourquoi? Parce que s'il y a un vote à traiter, un cookie peut être écrit, et vous ne pouvez pas écrire de cookies après que quelque chose d'autre ait été envoyé. L'appel à la méthode statique vote () retourne s'il n'y a pas les données POST appropriées à traiter.

    Ensuite, nous allons inclure tous les styles que nous avons écrits en tant que feuille de style séparée. De plus, nous allons inclure un style particulier juste pour IE qui a été mentionné plus tôt pour permettre à: hover psudo-class.

     

    Dans le CORPS de votre page HTML, vous déposerez le code PHP suivant pour insérer les sondages:

    $ a = new webPoll (array ('Quels sujets souhaiteriez-vous en savoir plus?', 'HTML & CSS', 'JavaScript', 'JS Frameworks (jQuery, etc)', 'Ruby / Ruby on Rails', ' PHP ',' MySQL ')); $ b = new webPoll (array ('Quelle est votre question?', 'Ne pas en avoir un', 'Pourquoi?', 'Quand?,' Où? '));

    C'est tout! Merci d'avoir lu. Des pensées, des questions ou des suggestions?