Ankety univerzálne (PHP + MySQL + CSS)

    10

    Najrôznejšie druhy ankiet sa stali súčasťou mnohých webov, a každý používateľ internetu sa s nimi nepochybne už stretol. Napriek vizuálnym rozdielom, ich podstatné znaky sú takmer identické. Z nášho pohľadu – ako programátorov týchto ankiet, je pochopiteľne jednoduchšie napísať si jeden univerzálny „hlasovací modul“ ako zakaždým písať jednotlivé ankety samostatne.

    Predtým, než si ukážeme konkrétne kódy pre konkrétnu technológiu (ako príklad použijeme nerozlučnú dvojicu PHP + MySQL), pokúsme sa definovať, čo od našich ankiet budeme požadovať. Budeme skôr konzervatívni, preto naše požiadavky neprekročia bežne zaužívanú funkcionalitu, čiže:

    • zobrazenie percentuálneho stavu výsledkov,
    • zobrazenie vizuálneho stavu výsledkov (simulácia stĺpcového grafu),
    • zobrazenie celkového počtu hlasov,
    • umožnenie hlasovať len raz (cookies).

    A samozrejme nesmieme zabudnúť na požiadavky univerzality, teda toho, čo nám uľahčí neskôr prácu. Môžeme pritom vychádzať z nasledovnej filozofie:

    • vizuálne formátovanie rôznych ankiet budeme riešiť priradením rôznych CSS tried, čiže samotný HTML kód ankiet bude rovnaký,
    • kód našeho hlasovacieho modulu bude rovnaký pre anketu s dvoma alebo s desiatimi možnosťami.

    Tu je ukážka toho, k čomu sa môžeme dopracovať.

    Na dosiahnutie našej funkcionality nevyhnutne potrebujeme:

    • tabulku s dátami,
    • funkciu na zobrazenie ankety (zobraz_anketu()),
    • funkciu na zápis hlasovania (hlasuj()),
    • vytvorenie predmetných kaskádových štýlov (odporúčam pozrieť zdrojový kód ukážky).

    SQL štruktúra našej univerzálnej tabuľky môže teda vyzerať napríklad takto:

    CREATE TABLE ankety (
        id int(11) DEFAULT ‚0‘ NOT NULL auto_increment,
        otazka varchar(255),
        odpovede tinytext,
        separator varchar(10),
        vysledky varchar(255),
        PRIMARY KEY (id)
    );

    Ako som vyššie spomenul, že vopred nevieme koľko odpovedí (možností) bude mať naša anketa, vyriešime to jednoducho tak, že všetky odpovede zapíšeme ako jeden reťazec, v ktorom budú hodnoty oddelené hodnotou riadka "separator". Teda hodnota našeho riadku odpovede (pre separator ":") môže vyzerať napr.: Áno:Nie .

    Riadok vysledky bude napĺňaný analogicky v tvare: počet hlasov pre 1. odpoveď separator počet hlasov pre 2. odpoveď…

    V tejto chvíli je už mnohým z Vás určite jasná filozofia našeho hlasovacieho modulu. Reťazce odpovede a vysledky si rozdelíme do poľa (funkciou explode()) a získame tak jednotlivé odpovede (možnosti) ako aj zastúpenie hlasov pre jednotlivé možnosti, z ktorých neskôr ľahko vypočítame ako absolútny počet hlasov, tak aj percentuálny pomer.

    Pokiaľ pozorný čitateľ namieta, že riadok "separator" je zbytočný, má do určitej miery pravdu. My ho tam však ponecháme, aby sme si zabezpečili maximálne možnú univerzálnosť.

    Skôr, ako si ukážeme jednotlivé funkcie, vysvetlime si ešte akým spôsobom budeme vizuálne zobrazovať percentuálny pomer. Ako jeden z parametrov predáme funkcii zobraz_anketu() názov obrázku (najlepšie 1px x 1px jednofarebný GIF), ktorý budeme "rozťahovať" podľa percentuálnych hodnôt (ako ďaľší parameter predávame šírku pre 100%, teda maximálnu veľkosť (šírku) stĺpca)…

    Funkcia zobraz_anketu() môže vyzerať napríklad takto:

    function zobraz_anketu($id, $cssClassId, $imgFile, $maxWidth)
    {    //select
        $result = MySQL_Query(„SELECT * FROM ankety WHERE id = ‚$id'“);
        $row = MySQL_Fetch_Array($result);
        //rozdelenie retazcov do pola
        $options = explode($row[‚separator‘],$row[‚odpovede‘]);
        $votes = explode($row[‚separator‘],$row[‚vysledky‘]);
        //zistime kolko je moznosti (odpovedi)
        $options_count = count($options);
        //zistime aky je pocet hlasov spolu
        for ($i=0; $i<$options_count; $i++)
        {  $votes_total += $votes[$i];
        }
        //zobrazenie (formatovanie) vysledkov
        for ($i=0; $i<$options_count; $i++)
        {    //vypocet dlzky stlpca grafu
            //nepovolime mensiu sirku ako napr. 2 px
            $min_width = 2;
            if ($votes_total != 0)
            {    $width = round($votes[$i] / $votes_total * $maxWidth);
                if ($width < $min_width) { $width = $min_width;}
            }
            else
            {    $width = $min_width; }
            //vypocet percentualnych hodnot
            $votes_total==0 ? $percentage = 0 : $percentage = round($votes[$i] / $votes_total * 100);
            //formatovanie HTML vystupu
            $tmp_output .= „<span><a href=\“anketa_spracuj.php?i=$id&a=$i\“>“.$options[$i].“</a>
              <span class=\“perc\“>($percentage%)</span>
              <a href=\“anketa_spracuj.php?i=$id&a=$i\“>
              <img src=\“$imgFile\“ alt=\““.$options[$i].“\“ width=\“$width\“ height=\“10\“>
              </a></span>“;
        }
        //vysledny HTML output
        $html_output = „<div id=\“$cssClassId\“><span class=\“otazka\“>
          „.$row[‚otazka‘].“</span>$tmp_output <span class=\“spolu\“>
          Počet hlasov: $votes_total</span></div>“;
        return $html_output;
    }

    Do súboru anketa_spracuj.php umiestnime funkciu ktorá zapíše náš hlas, teda funkciu hlasuj():

    function hlasuj($id, $answer)
    {    //definovanie globalnych premennych
        global $HTTP_COOKIE_VARS;
        //kontrola ci uz nebolo hlasovane
        if ($HTTP_COOKIE_VARS[‚anketa‘.$id.’Voted‘])
        { return; }
        //DB select
        $result = MySQL_Query(„SELECT odpovede, separator, vysledky FROM ankety WHERE id = ‚$id'“);
        $row = MySQL_Fetch_Array($result);
        //rozdelenie retazca odpovedi do pola
        $options = explode($row[‚separator‘],$row[‚odpovede‘]);
        //zistime kolko je moznosti (odpovedi)
        $options_count = count($options);
        //ak hlasujem prvy krat (retazec vysledky je prazdy)
        //tak naplnim retazec v tvare 0separator0 …
        if (empty($row[‚vysledky‘]))
        {    for ($i=0; $i<$options_count; $i++)
            {    $tmp .= ‚0‘.$row[‚separator‘];
            }
            //odstranime separator z konca retazca
            $row[‚vysledky‘] = substr ($tmp, 0 , strlen($tmp)-strlen($row[‚separator‘]));
        }
        //rozdelenie retazca vysledkov do pola
        $votes = explode ($row[‚separator‘],$row[‚vysledky‘]);
        //pridanie hlasu
        $votes[$answer]++;
        //zlucenie hodnot pola spat do retazca
        $vote_results = implode ($row[‚separator‘], $votes);
        //zapis vysledkov do DB
        $result = MySQL_Query(„UPDATE ankety SET vysledky = ‚$vote_results‘ WHERE id = ‚$id'“);
        //zapis cookie v tvare napr. anketa1Voted = 1
        //nastavenie expiracie na 7 dni
        SetCookie(‚anketa‘.$id.’Voted‘, ‚1‘, time()+(7*24*60*60) );
        //navrat
        return;
    }

    Po tom, čo táto funckia zapíše náš hlas, pomocou funkcie Header() presmerujeme návštevníka späť, teda:

    Header(„Location: $HTTP_REFERER“);

    V tejto chvíli máme pripravené nevyhnutné funkcie aj tabuľku. Ostáva nám už len naplniť tabuľku požadavanými dátami, napr.:

    INSERT INTO ankety VALUES ( ‚1‘, ‚Hlasujete v takýchto anketách?‘, ‚Áno:Nie‘, ‚:‘,“);

    K správnemu fungovaniu potrebujeme samozrejme otvorené spojenie s databázou…

    $DB_server = „xy“; $DB_name = „xy“; $DB_user = „xy“; $DB_psw = „xy“;
    $DB_conn = MySQL_Connect($DB_server,$DB_user,$DB_psw);
    MySQL_Select_DB($DB_name);
    //Volanie našej funkcie (ako parameter $cssClassId predáme napr. triedu „anketa1“)
    $anketa1 = zobraz_anketu(1, ‚anketa1‘, ‚color1.gif‘, 100);
    mysql_close($DB_conn);

    Po tom, čo sme si inicializovali premennú $anketa1 môžeme jednoducho vložiť do našej stránky tieto riadky…

    <?php echo $anketa1; ?>

    Vyššie uvedenými funkciami sme si zabezpečili správne fungovanie našich ankiet. Na vizuálne zobrazenie použijeme kaskádové štýly, ktoré nám poskytujú úžasný komfort. Problematikou kaskádových štýlov sa však detailne zaoberať nebudeme. Ukážeme si iba jednoduchý príklad (odporúčam taktiež pozrieť zdrojový kód ukážky).

    #anketa1 { width: 150px; border: 1px solid grey; background-color: white; font-family: sans-serif; font-size: 11px; padding: 7px; }
    #anketa1 span { display: block; }
    #anketa1 a { color: maroon; text-decoration: none; font-weight: bold; }
    #anketa1 img { border: 0px; margin-top: 2px; margin-bottom: 6px; }
    #anketa1 .otazka { font-weight: bold; margin-bottom: 7px; }
    #anketa1 .perc { display: inline; }

    V rámci rekapitulácie si načrtnime, ako by mohol vyzerať konrétny súbor napr. anketa.php

    <?php
    //funkcia zobraz_anketu()…
    //otvorenie spojenia s DB…
    //samotné volanie funkcie:
    $anketa1 = zobraz_anketu(1, ‚anketa1‘, ‚color1.gif‘, 100);
    //zatvorenie spojenia s DB…
    ?>
    <!DOCTYPE HTML PUBLIC „-//W3C//DTD HTML 4.0 Transitional//EN“>
    <html><head><title>Anketa</title>
    <style type=“text/css“>
    <!–
    /*definícia pre #anketa1*/
    –>
    </style>
    </head><body>
    <?php echo $anketa1; ?>
    </body></html>

    Pre úplnosť treba uviesť aj schému súboru anketa_spracuj.php, teda:

    <?php
    //funkcia hlasuj()…
    //otvorenie spojenia s DB…
    //samotné volanie funkcie:
    hlasuj($i, $a);
    //zatvorenie spojenia s DB…
    //presmerovanie spat
    Header(„Location: $HTTP_REFERER“);
    ?>

    Na záver treba poznamenať, že uvedené funkcie sa dajú značne rozšíriť. Napríklad pomocou knižnice GD si môžeme obrázky sami vytvárať, prípadne priraďovať každému stĺpcu inú farbu atď. Zdrojový kód ukážky si môžete stiahnuť tu.

    Starší komentáře ke článku

    Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

    10 Příspěvků v diskuzi

    1. Nie php5 samozrejme neexistovalo, ale podľa dátumu posledných komentárov vašu anketu očividne ľudia sťahujú a skúšajú nasadiť na svoje weby (na ktorých dnes beží prevažne len php5), preto by sa ich patrilo upozorniť, aby tak nerobili.

      Ale mimochodom bezpečnostné zraniteľnosti v ankete sa dali opraviť aj v roku 2001.

    Odpovědět