12. díl - Anketa - Administrační rozhraní

PHP Databáze pro začátečníky Anketa - Administrační rozhraní

(pokračování tohohle)

Anketní otázky a odpovědi sice můžeme tvořit a upravovat přímo pomocí příkazů SQL, ale to je poměrně pracné a hrozí, že se někde překlepneme. Pokud jste dost líní na to, abyste investovali nemalé množství práce do stránky, která vám následně trošku práce ušetří, čtěte dál :-).

Co všechno budeme potřebovat?

  • Formulář na vytvoření nové ankety. Bude v něm textové políčko pro napsání otázky a políčko pro napsání kódu (tedy pokud si ho nenecháváme generovat auto_incrementem - předpokládám, že ne).
  • Formulář pro výběr ankety k úpravám. To může být roletová nabídka, sada odkazů nebo cokoli, co vás napadne. Pro jednoduchost to předvedu na těch odkazech.
  • Formulář pro přidání nové odpovědi. Jedno prázdné textové políčko. Protože ho budeme používat ze všech nejčastěji, mělo by být na stránce někde nahoře.
  • Formulář pro editaci otázky a odpovědí vybrané ankety. V něm bude jedno textové políčko pro každou odpověď, původní texty v nich budou předvyplněné. U každé odpovědi bude odkaz na její smazání, u otázky pak jeden na smazání celé ankety.

Každý formulář samozřejmě bude mít i svoje odesílací tlačítko.

V následujícím textu postupně uvedu jednotlivé formuláře a příslušné vyhodnocovací algoritmy. Předpokládám, že všechno pojede v jednom skriptu nazvaném tvorbaanket.php. O rozložení na stránku, vzhled a podobné nepodstatné drobnosti už se touhle dobou doufám dokážete postarat sami :-).

Zatím nebudeme řešit přihlašování, ochranu heslem, antispam a podobné věci. Předpokládám, že tenhle jednoúčelový skript budeme nahrávat na server vždycky jenom na chvíli a po použití ho zase smažeme, takže se k němu nikdo nestihne dostat a zneužít nezabezpečený přístup. Ze stejného důvodu se protentokrát můžeme vykašlat i na ochranu proti SQL injekci.

Vytvoření nové ankety

Formulář:

<form action="tvorbaanket.php" method="post">
<input type="text" name="tvorotazka" value="">
<input type="text" name="tvorkod" value="">
<input type="submit" value="Vytvoř anketu">
</form>

Vyhodnocení:

if (isset($_POST['tvorotazka']) and isset($_POST['tvorkod']))
 {
 //kontrola, jestli uz nahodou neexistuje:
 $vysledek=mysql_query("select * from otazky where kodankety=".$_POST['tvorkod'],$spojeni);
 if (mysql_num_rows($vysledek)==0)
  {
  if (mysql_query("insert into otazky values (".$_POST['tvorkod'].",'".$_POST['tvorotazka']."')",$spojeni))
          echo 'Anketa vytvořena.';
     else echo 'Anketu se nepodařilo vytvořit.';
  };
 else echo 'Anketa s tímhle kódem už existuje, zkus zadat nějaký jiný.';
 };

Pozn.: z hlediska pohodlí by bylo nejlepší, aby se nově vytvořená anketa hned automaticky vybrala pro úpravy. Ale to už nechám na vás. Nápověda: vyhodnotíme výstup a pak pomocí příkazu header (viz dříve) skočíme na stránku s adresou upravenou podle následujícího odstavce.

Seznam anket s výběrem

Dejme tomu, že to bude jednoduchý seznam odkazů. Teď ale pozor: informaci o tom, která anketa je vybraná, musíme někudy předat. S odkazy nemáme jinou možnost než metodu Get neboli vepsání hodnoty přímo do adresy stránky. Dejme tomu, že si tu proměnnou pojmenujeme vybranaanketa. Hlavně je potřeba nezapomenout, že ji pak musíme neustále předávat i z dalších formulářů, jinak by se nám výběr ztratil.

Nejdřív vyhodnocení - tohle musíme připravit vždycky:

$vybranaanketa = isset($_GET['vybranaanketa']) ? $_GET['vybranaanketa'] : '';

Pro ilustraci jsem použil céčkovský špek zvaný podmíněný výraz. Obecně se zapisuje jako Podmínka?Hodno­ta1:Hodnota2 a znamená: pokud je daná Podmínka pravdivá (true), výsledkem výrazu je Hodnota1, jinak Hodnota2. Co se týče priority těchto operátorů, je úplně nejnižší. To mimo jiné znamená, že jestli chcete třeba sestavit řetězec pomocí operátoru "." a jako některé části použijete podmíněné výrazy, musíte je uzavřít do (závorek), jinak by se tečky vyhodnotily jako první, přilepily by vám kousky řetězce k podmínce a druhé hodnotě a vyšel by vám z toho nesmysl.

A teď ten seznam:

$vysledek=mysql_query("select * from otazky",$spojeni);
if (mysql_num_rows($vysledek)==0)
 {
 echo '<p>Zatím tu žádnou anketu nemáme.</p>';
else:
 echo '<ul>';
 while ($radek=mysql_fetch_array($vysledek))
  if ($vybranaanketa==$radek['kodankety'])
         echo '<li>'.$radek['kodankety'].': '.$radek['otazka'].' (aktuálně vybraná)</li>';
    else echo '<li><a href=tvorbaanket.php?vybranaanketa='.$radek['kodankety'].'">'
              .$radek['kodankety'].': '
              .$radek['otazka'].'</a></li>';
 echo '</ul>';
 };

Přidání otázky k vybrané anketě

Celkem jednoduchá záležitost. Pozor je potřeba dát jenom na správné ošetření vybrané ankety (předpokládám, že proměnnou $vybranaanketa máme připravenou z předchozího odstavce). Formulář:

if ($vybranaanketa<>'')
 {
 echo '<form action="tvorbaanket.php?vybranaanketa='.$vybranaanketa".' method="post">';
 echo '<input type="text" name="pridejodpoved" value="">';
 echo '<input type="submit" value="Přidej odpověď">';
 echo '</form>';
else:
 echo 'Žádná anketa není vybraná.';
 };

Tady celkem není co řešit, snad jenon by šlo doplnit políčko pro zadání počátečního počtu hlasů. Ale to už je detail.

Vyhodnocení:

if (($vybranaanketa<>'') and isset($_POST['pridejodpoved']) and ($_POST['pridejodpoved']<>''))
 if (mysql_query("insert into odpovedi values (null, $vybranaanketa, 0, '".$_POST['pridejodpoved']."')",$spojeni))
        echo 'Odpověď vložena.';
   else echo 'Odpověď se nepodařilo vložit.';

Hlášení o úspěšnosti je víceméně zbytečné (odpověď buď uvidíme v následujícím formuláři nebo ne), dal jsem ho sem jenom pro úplnost.

Úpravy vybrané ankety

Tohle je nejsložitější část celého skriptu, ale v podstatě není úplně nezbytně nutná, takže jestli chcete, můžete ji vynechat (jenom to mazání byste pak museli dělat ručně).

Formulář:

if (($vybranaanketa<>'')
 {
 echo '<form action="tvorbaanket.php?vybranaanketa='.$vybranaanketa.'" method="post">';
 //otázka:
 $vysledek=mysql_query("select otazka from otazky where kodankety=$vybranaanketa",$spojeni);
 if ($radek=mysql_fetch_row($vysledek))
         echo 'Otázka: <input type="text" name="editotazka" value="'.$radek[0].'"> '
              .'<a href="tvorbaanket.php?vybranaanketa='.$vybranaanketa.'&smazanketu=jo">Smaž celou tuhle anketu</a>';
    else echo 'Vybraná anketa neexistuje.';
 //odpovědi:
 echo '<br>Odpovědi:<br>';
 $vysledek=mysql_query("select id, odpoved from odpovedi where kodankety=$vybranaanketa order by id asc",$spojeni);
 while ($radek=mysql_fetch_array($vysledek))
  {
  echo '<input type="text" name="editodpoved'.$radek['id'].'" value="'.$radek['odpoved'].'"> '
       .'<a href="tvorbaanket.php?vybranaanketa='.$vybranaanketa.'&smazodpoved='.$radek['id'].'">Smaž tuhle odpověď</a><br>'
  };
 echo '<input type="submit" value="Ulož změny">';
 echo '</form>';
 };
else echo 'Žádná anketa není vybraná.';

Jak vidíte, metody Get a Post se dají kombinovat: kód vybrané ankety posíláme přes adresu (Get) a obsah textových políček jinudy (Post).

Otázku si nejdřív vytáhneme z databáze. Pokud ji tam najdeme (jako že asi jo, jinak bychom se na ni nemohli přes seznam doklikat), vypíšeme ji v textovém políčku. K ní ještě přidáme odkaz na smazání ankety - ten předá proměnnou $_GET['smazanketu'] s hodnotou 'jo'. Na hodnotě nám nezáleží, anketu ke smazání už nám jednoznačně určuje proměnná $vybranaanketa.

Odpovědi se od otázky zas až tak moc neliší, jenom je jich víc, takže musíme použít cyklus. Také je potřeba jednotlivá políčka navzájem nějak odlišit: na to použijeme položku id, kterou připojíme ke jménu (name). Mazací odkaz funguje podobně jako mazadlo otázek, ale tentokrát kód ankety na identifikaci nestačí, proto si pro proměnnou $_GET['smazod­poved'] připravíme id odpovědi.

Tlačítko "Ulož změny" je tu proto, aby bylo čím odeslat hodnoty z textových polí. Kliknutí na nějaký mazací odkaz formulář neodešle, na to pozor.

A nakonec vyhodnocení. Setkáme se tu s něčím, s čím jsme se ještě nesetkali: s neznámým počtem vstupních parametrů, u kterých ani přesně nevíme, jak se jmenují. Začnu kódem a potom si to vysvětlíme:

if (($vybranaanketa<>'')
 {

 //úprava otázky:
 if(isset($_POST['editotazka']))
  mysql_query("update otazky set otazka='".$_POST['editotazka']."' where kodankety=$vybranaanketa",$spojeni);

 //funkce určující, jestli daná věc je jméno proměnné s odpovědí:
 function jetoodpoved($co)
 {
 return(substr($co,0,11)=='editodpoved');
 }

 //úprava odpovědí:
 $klice=array_keys($_POST);
 $klice=array_filter($klice,'jetoodpoved');
 foreach ($klice as $klic)
  {
  $idecko=substr($klic,11);
  mysql_query("update odpovedi set odpoved='".$_POST[$klic]."' where id=$idecko",$spojeni);
  };

 //případné smazání ankety (tj. otázky a všech odpovědí, které k ní patří):
 if(isset($_GET['smazanketu']))
  {
  mysql_query("delete from odpovedi where kodankety=$vybranaanketa",$spojeni);
  mysql_query("delete from otazky where kodankety=$vybranaanketa",$spojeni);
  $vybranaanketa=''; //to aby bylo jasné, že tahle anketa už neexistuje
  };

 //případné smazání některé odpovědi:
 if(isset($_GET['smazodpoved']))
  mysql_query("delete from odpovedi where id=".$_GET['smazodpoved'],$spojeni);

 };

Uf. Takže co jsme to vlastně udělali?

  1. Úprava otázky - celkem triviální věc. Pokud nám příslušná proměnná z Postu přišla (tj. pokud jsme se sem dostali odesláním formuláře), nahradíme její hodnotou hodnotu v databázi otázek. O jednoznačnou identifikaci se postará kód vybrané ankety. Úspěšnost už ani netestuju - buď se to povede, nebo se nám ve formuláři objeví zase ta původní hodnota a pak je jasné, že se to nepovedlo. Ale prakticky se to stejně vždycky povede.
  2. Filtrovací funkce - řekne nám, jestli daný řetězec začíná na 'editodpoved'. Funkce substr(Řetězec,Po­zice,Délka) vrací úsek z daného Řetězce začínající od dané Pozice (počítáno od nuly) a o dané Délce, nebo pokud Délka není zadaná, tak bere všechno až do konce Řetězce. Filtrovací funkci budeme potřebovat o kousek dál.
  3. Úprava odpovědí - tady už to trošičku houstne. Teoreticky by nebyl problém projít foreachem celé pole $_POST, u každé položky filtrovací funkcí (nebo přímo) otestovat klíč jestli je to jméno odpovědi, a jestli jo, její hodnotu uložit do tabulky. Ale já jsem se rozhodl pro zpestření použít trochu jiný postup. Funkcí array_keys jsem z pole $_POST vytáhl do samostatného pole klíče. Tohle nové pole je indexováno čísly od nuly a původní klíče má jako hodnoty. V dalším kroku jsem použil funkci array_filter, která z daného pole vyhodí všechny prvky, pro které funkce v druhém parametru (v našem případě "jetoodpoved", zadává se takhle jménem jako text) dává hodnotu false. Tím jsme dostali pole, které obsahuje pouze jména proměnných, které nás zajímají. Zbytek už je v podstatě triviální: každé toto jméno vezmeme, vytáhneme z něj id (víme, že začíná na pozici 11 a pokračuje až do konce jména), použijeme ho jako identifikační podmínku a přepíšeme text odpovědi.
  4. Smazání ankety - nejdřív se podíváme, jestli přes Get přišla příslušná proměnná (tj. jestli jsme se sem dostali kliknutím na mazací odkaz). Pokud ano, smažeme všechny otázky a odpovědi, které patří k této anketě.
  5. Smazání odpovědi - jednodušší než úpravy textů, protože smazat se dá vždycky jenom jedna, navíc její id dostaneme až pod nos. Myslím, že tady není co vysvětlovat.

A to je vše, přátelé!

Na to, jaká je to blbost, jsme si toho o anketách napsali až až :-). Doufám, že uvedené příklady aspoň k něčemu budou.

Jestli dáváte přednost souvislým textům před rozkouskovaným seriálem, je vám jako obvykle k dispozici alternativní verze tohoto trojčlánku.

Příště se zaměříme víc na texty a napíšeme si (konečně) něco užitečnějšího: návštěvní knihu.


 

  Aktivity (1)

Článek pro vás napsal Mircosoft
Avatar
Autor je amatérský pascalista, assemblerista a bastlíř. Profesionálně psal nebo píše v HLASM, Rexxu, Cobolu, ST, LAD, FBD, PHP, SQL, JS, Basicu a pár dalších jazycích, které kupodivu stále existují a používají se :-).

Jak se ti líbí článek?
Celkem (4 hlasů) :
2.752.752.75 2.752.75


 



 

 

Komentáře
Zobrazit starší komentáře (5)

Avatar
David Čápka
Tým ITnetwork
Avatar
David Čápka:

<> označuje nerovnost, stejně jako !=, autor má bohužel rád nestandardní zápisy.

Odpovědět 9.7.2015 10:48
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Daniel Vítek
Tým ITnetwork
Avatar
 
Odpovědět  +1 9.7.2015 11:06
Avatar
loading84
Člen
Avatar
loading84:

Stejně je to debilní protože tady není ověřovaní řetězce. Je tam jenom

$vysledek=mysql_query("select * from otazky where kodankety=".$_POST['tvorkod'],$spojeni);

ověřuje se jenom kod nikoliv textový řetězec. Ten jsem chtěl ověřit ale nepřišel jsem na to jak. A tohle bohužel nefunguje a už nad tím nebudu důmat.

$tvorotazka=$_POST['tvorotazka'];
$tvorkod=$_POST['tvorkod'];
$vysledek=mysql_query("select otazky, kodankety from otazky where kodankety=$tvorkod or otazka=$tvorotazka",$spojeni);
 
Odpovědět 7.10.2015 18:31
Avatar
loading84
Člen
Avatar
loading84:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  <meta http-equiv="Content-type" content="text/html; charset=UTF-8">

  <title>Anketa</title>
  </head>
  <body>
   <?php
         mb_internal_encoding('UTF-8');
        $spojeni=mysql_connect('localhost','root',' ');
        if(!$spojeni) die('Nepodarilo se pripojit k databazi');


        mysql_set_charset('utf8');
        mysql_select_db('anketa',$spojeni);


        if($_GET['hlasujpro'] =='')
        $vysledekkk=mysql_query("SELECT otazka, kodankety FROM otazky",$spojeni);
        while ($radek=mysql_fetch_array($vysledekkk))
        {
        echo '<table>';
        echo '<tr><td>';
        echo '<a href="vyber-ankety.php?hlasujpro='.$radek['kodankety'].'">'.$radek['otazka'].'</a>';
        echo '</td></tr>';
        echo '</table>';
        };

        $promena=$_GET['hlasujpro'];

        if(is_numeric($promena))
        {
        $vysledek=mysql_query("SELECT otazka FROM otazky where kodankety=$promena",$spojeni);
        $radek=mysql_fetch_row($vysledek);
        echo $radek[0];
        }


        if(!is_numeric($_GET['hlasujpro']) && ($_GET['hlasujpro'] !=''))
        echo 'Co to na me zkousis podvodniku';

        $vysledekk=mysql_query("SELECT * FROM otazky WHERE kodankety=$promena",$spojeni);
        if((mysql_num_rows($vysledekk)==0) && ($_GET['hlasujpro'] !=''))
                 {
                 echo 'Anketa neexistuje';
                 }

     ?>

    </body>
</html>

Výběr ankety jsem udělal takhle... vubec neroozumim tvému postupu.

 
Odpovědět 7.10.2015 20:12
Avatar
Mircosoft
Redaktor
Avatar
Odpovídá na loading84
Mircosoft:

Ověřuju jenom kód, protože ten musí být pro každou anketu unikátní. Otázka unikátní být nemusí - třeba "Jak se vám tohle líbí?" se může opakovat každou chvíli.

Ten kousek, co ti nefunguje, nefunguje kvůli neohraničenému řetězci v příkazu. Takhle by to mělo být v pořádku:

$vysledek=mysql_query("select otazky, kodankety from otazky where kodankety=$tvorkod or otazka='$tvorotazka'",$spojeni);

Díky za podněty.

 
Odpovědět 7.10.2015 22:55
Avatar
loading84
Člen
Avatar
Odpovídá na Mircosoft
loading84:

Diky, už mi to funguje. Jinak ty věci co tu děláš, já dělám trochu jinak.

 
Odpovědět 8.10.2015 11:12
Avatar
loading84
Člen
Avatar
loading84:
function jetoodpoved($co)
{
return(substr($co,0,11)=='editodpoved');
}

tenhle kus kodu nechapu, kde se tam vzala 11 a nula.

 
Odpovědět 10.10.2015 12:46
Avatar
IT Man
Redaktor
Avatar
Odpovídá na loading84
IT Man:

http://www.itnetwork.cz/…y-php-manual
Ta funkce substr() je stejná jako mb_substr(). mb_substr() umí navíc UTF-8 (pokud se nastaví). :)

Editováno 10.10.2015 12:53
Odpovědět 10.10.2015 12:53
Když nevíš jak dál, podá ti ruku někdo, od koho by jsi to nečekal. A tu šanci musíš přijmout!
Avatar
Mircosoft
Redaktor
Avatar
Odpovídá na loading84
Mircosoft:

Máš řetězce "editodpoved1", "editodpoved2", "kravina10", "editodpoved57" a "houba". Jak poznáš, které z nich začínají na "editodpoved"? 11 je počet znaků ve slově "editodpoved", 0 je index začátku řetězce. Manuál k PHP řekne zbytek ;-).

Jinak dneska bych to už taky udělal jinak. Proměnné bych si pojmenoval editodpoved[1], editodpoved[2] atd. a pak by šly rovnou projít jako pole bez nutnosti filtrování.

 
Odpovědět 10.10.2015 14:55
Avatar
loading84
Člen
Avatar
Odpovídá na Mircosoft
loading84:

To mě právě taky napadlo. Ja tyhle články dělám trochu jinak. Jinak se teď pokladam do objektové programka. Tohle bylo jenom na rozehřátí. Ale díky za odpovědi. Jsem rád, že někdo tady reaguje.

 
Odpovědět 10.10.2015 18:34
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 15. Zobrazit vše