Typický problém je, že databáze vypíše například seznam výrobků, které jsou na skladě, nebo seznam knih, které lze vypůjčit, a uživatel si má kliknout na jednu z nich, aby se vybrala. Výsledek se z hlediska naší aplikace především zapíše do databáze (praktická aplikace by možná ještě poslala e-mail, vytiskla formulář a podobně). Nastíníme několik možností:

Správné řešení

Kliknutím na zvolený název knihy nebo obrázek výrobku spustíme funkci připravenou v Javascriptu, která nám zkontroluje zadaná data a především sestaví volání následujícího formuláře; náš formulář tedy nebude mít žádné tlačítko typu submit, nebo pokud ano, bude volat Javascript. Výhodou takového řešení je, že Javascript zkontroluje smysluplnost odesílaných dat. Protože jsme ale potřebné funkce zatím neprobírali, odkazuji zde na přednášky, kde se Javascript vyučuje podrobněji.

Mezipoznámka - datum v MySQL

Asi by bylo správnější datum generovat v php - k tomu se ještě dostaneme. Prozatím můžeme pro vložení datumu do naší databáze použít přímo funkci jazyka SQL, a to buď CURDATE(), nebo NOW() - oboje způsobí vložení obsahu proměnné typu datetime, v druhém případě včetně přesného času. Funkci uvedeme přímo jako text mezi apostrofy, protože se odesílá MySQL serveru, který si ji zpracuje sám.

Pro zadávání datumu by bylo nejlepší použít funkci kalendáře v JavaScriptu, po internetu je jich mnoho na stažení - nejznámější je asi OpenCalendar. Podrobněji viz například http://www.navioo.com/javascript/dhtml/GUI_Components_227.dhtml, http://www.mattkruse.com/javascript/calendarpopup/ nebo http://www.javascripttoolbox.com/. Můžete se k tomu vrátit, až budete aplikaci dokončovat.

Přímo zapsané odkazy

Nejsnazší možností je psát přímo odkazy - formulář pak nebude vůbec žádný. Řešení na straně serveru bude velmi jednoduché, máme stálé jméno proměnné a mění se její hodnota (to by u tlačítka nešlo, protože ta je na něm napsaná):

<table border=1>
<tr><th>typ<th>cena/km<th>objednat
<tr><td><a href="rent.php?o=1">Audi A100</a><td>12
<tr><td><a href="rent.php?o=2">Renault 12</a><td>6
<tr><td><a href="rent.php?o=3">Citroen 2CV</a><td>4
</table>

Ve skutečnosti ještě musíme předat alespoň id zákazníka, například pro zákazníka číslo pět a Citroen by odkaz mohl být "rent.php?z=5&o=3". Tento úsek html kódu by vygeneroval následující skript (předpokládejme nastavení $id_z z předchozího formuláře):

<?php
mysql_connect('mysql.webzdarma.cz','zpp','tudlenudle')
 or die('chyba:'.mysql_error() );
mysql_select_db('zpp');
$result=mysql_query('SELECT id,type,cost FROM auta ORDER BY id;');

echo "<table border=1>\n<tr><th>typ<th>cena/km<th>objednat\n";
while ($row=mysql_fetch_row($result)) {
echo "<tr><td><a href=\"rent,php?z=$id_z&o=$row[0]\"";
echo ">".$row[1]."</a><td>".$row[2]."\n";
}
echo "</table>";

mysql_close(); 

?>

Protože nesmíme půjčit již jednou půjčené auto, musíme příkaz SELECT rozšířit o podmínku WHERE komu="0", a udržovat tento sloupec tak, aby zde u půjčených aut bylo (nenulové) číslo zákazníka (v databázích, kde se čísluje od nuly, by se u volných psalo "-1", ale to není náš případ - "int not null auto increment primary key" parametry u id zákazníka generují čísla od jedničky.

Trochu nepříjemné je, že při použití zápisu do textu odkazu je vždy použita metoda "get", tj. uživatel vše po odeslání uvidí v adresní řádce. V některých případech to může být výhoda, například u serveru Google si takto můžeme uložit zvláště zdařilý dotaz. Pokud se vám podaří vymyslet aplikaci, kde se to hodí, můžete použít i tuto zjednodušenou metodu.

Pro zápis do databáze pro nás bude nejsnazší použít opět funkci "mysql_query". Pokud máme v proměnné id_a "id" auta a v proměnné id_z "id" z tabulky zákaznící, můžeme zapsat novou výpůjčku do tabulky výpůjček příkazem

'INSERT INTO vypujcky VALUES ("'.$id_z.'", "'.$id_a.'", CURDATE());'

Podrobněji viz např. http://www.w3schools.com/PHP/php_mysql_insert.asp. Současně si ale musíme do tabulky s nabízenými auty zapsat, že toto již nenabízet:

'UPDATE auta SET komu="'.$id_z.'" WHERE id="'.$id_a.'";'

Podmínka WHERE vymezuje, kde všude data opravit. Pokud se vynechá, příkaz opraví všechny řádky v tabulce. Vzhledem k tomu, že zákazník si jistě vypůjčil jen jednou auto (viz tabulka výpůjček - jen jeden nový řádek), možná by se mohl přidat parametr LIMIT =1. Pak bude opraven jen první výskyt. Toto opatření by ovšem mělo být nadbytečné, protože "id" je primární klíč a u toho nám SQL server hlídá, aby nebylo možné vložit duplicitní data.

Vyhodnocení (zamluvení auta) by pak provedl například následující php script ("rent.php"):

<?php
$id_z=$_GET["z"];
$id_a=$_GET["o"];
mysql_connect('mysql.webzdarma.cz','zpp','tudlenudle')
 or die('chyba:'.mysql_error() );
mysql_select_db('zpp');

$result=mysql_query('INSERT INTO vypujcky VALUES ("'.$id_z.'", "'.$id_a.'", CURDATE());');
$result=mysql_query('UPDATE auta SET komu="'.$id_z.'" WHERE id="'.$id_a.'";');

mysql_close(); 

?>

Ještě nám chybí dotaz a ošetření chyby po zápisu do databáze, například za každým voláním mysql_query doplnit před středník oblíbený obrat "or die(...)".
Nyní je na zvážení, jak upravit SQL příkazy (SELECT), aby vypisovaly jen to, co je třeba...

Tlačítka Submit

Pokud nechceme použít javascript, je asi nejsnazším postupem, že každé tlačítko v tabulce bude samo o sobě submitem; aby se poznalo, které bylo stisknuto, bude i každé samo o sobě formulářem. Zdrojový kód tabulky, kterou máme v php vygenerovat, bude vypadat asi následovně:

<table border=1>
<tr><th>typ<th>cena/km<th>objednat
<tr><td>Audi A100<td>12<td>
<Form action="rent.php" method="post">
<input type="submit" name="Audi" value="objednat">
</Form>
<tr><td>Renault 12<td>6<td>
<Form action="rent.php" method="post">
<input type="submit" name="Renault" value="objednat">
</Form>
<tr><td>Citroen 2CV<td>4<td>
<Form action="rent.php" method="post">
<input type="submit" name="Citroen" value="objednat">
</Form>
</table>

Při vyhodnocování se pak budeme spíše ptát, zda $_POST['Audi'] == true, než jakou má hodnotu (vždy "objednat").
Uvozovky do textu zapíšeme buď pomocí apostrofů, nebo před ně napíšeme znak obrácené lomítko ( \" ). Výše uvedenou tabulku pak můžeme vygenerovat pomocí php kódu (je vynechán předchozí a následující html kód):

<?php
mysql_connect('mysql.webzdarma.cz','zpp','tudlenudle')
 or die('chyba:'.mysql_error() );
mysql_select_db('zpp');

$result=mysql_query('SELECT id,type,cost FROM auta ORDER BY id;');

echo "<table border=1>\n<tr><th>typ<th>cena/km<th>objednat";
while ($row=mysql_fetch_row($result)) {
echo "<tr>";
echo "<td>".$row[1]."<td>".$row[2]."<td>";
echo '<Form action="rent.php" method="post">\n<input type="submit" name="'
 .'id'.$row[0].'" value= "objednat">';
echo '\n</Form>\n'
}
echo "</table>";

mysql_close(); 
?>

Ve zbytku html kódu by měly následovat nějaké odkazy na jiné php stránky, pokud by náhodou došlo k tomu, že se nevybere ani jedna řádka, a nebylo by tedy na co kliknout.

Program takto ale fungovat nemůže. Jako první je třeba dodat, že se mají nabízet jen ta auta, která nejsou právě vypůjčená. Řekněme, že tabulka obsahuje ještě sloupec "vypujceno", který obsahuje id zákazníka, resp. nulu, pokud není půjčené:

SELECT id,type,cost FROM auta WHERE vypujceno="0" ORDER BY id;

Další poznámka je, že uživatel by měl být přihlášen, a jeho login name a heslo by se mělo předávat v rámci formuláře, tj. musíme přidat ještě text

echo '<input type=hidden name=user value='.$_POST["user"].'>;

echo '<input type=hidden name=pwd value='.$_POST["pwd"].'>;

Zpracování by urychlilo, kdybychom po přihlášení zákazníka si poznamenali také jeho ID, protože již jsme je stejně našli. Tím bychom ale ohrozili zabezpečení naší aplikace - při předávání dat mezi formuláři si šikovný uživatel samozřejmě může data jakkoli měnit, vše je proto nutné stále znovu prověřovat.

Výsledná data z formuláře budeme muset ošetřit výrazem typu:

... if ($_POST['id_3'] == true) ...

Naštěstí nám zkontrolování jména zadané proměnné usnadní vlastnosti jazyka php. Buď bychom se mohli ptát

$id_a = 0;
for ($i=1,$i<10,i++) { if ($_POST["id_$i"] == true) {$id_a = $i; }; };

, nebo přímo použijeme cyklus foreach a požádáme nejen o hodnotu, ale i o jméno proměnné v asociativním poli $_POST:

foreach ($_POST as $key => $value) {if (substr($key,0,3)=="id_") {$id_a = substr($key,3)}};

... ale pak $id_a je typu text a mělo by se převést na číslo - ? - to by udělala třeba funkce
list($id_a) = sscanf(substr($key,3), "%d");
, ale podle všeho to není třeba. Navíc - při sepisování příkazu SELECT je nám úplně jedno, co je v proměnné, stejně posíláme text.

Poznámka - www.php.net/manual uvádí příklad automatického převodu, když místo čísla dosadíme řetězec:

Konverze řetězců na čísla

Když je řetězec vyhodnocován v kontextu, kde by mělo být číslo, výsledná hodnota je dle následujících pravidel:

Pokud řetězec neobsahuje znaky '.', 'e', nebo 'E' a jeho numerická hodnota se vejde do rozsahu typu integer (viz konstanta PHP_INT_MAX), pak řetězec bude vyhodnocen jako integer. Ve všech ostatních případech bude vyhodnocen jako float.

Hodnota je dána počáteční částí řetězce. Pokud řetězec začíná platnou numerickou částí, pak se vyhodnotí (podle výše uvedených pravidel), jinak řetězec nabyde nulové hodnoty (0, typu integer). Platná numerická data mohou začínat znaménkem, následovaným jedním nebo více číslicemi, mezi kterými může být nejvýše jedna desetinná tečka, a případně může následovat exponent (písmeno e nebo E, následované případným (nepovinným) znaménkem a jednou nebo několika číslicemi.

<?php
$foo "10.5";                     // $foo je float (11.5)
$foo "-1.3e3";                   // $foo je float (-1299)
$foo "bob-1.3e3";                // $foo je integer (1)
$foo "bob3";                     // $foo je integer (1)
$foo "10 Malých prasátek";       // $foo je integer (11)
$foo "10.2 malých prasátek"// $foo je float (14.2)
$foo "10.0 prasátek " 1;           // $foo je float (11)
$foo "10.0 prasátek " 1.0;         // $foo je float (11)     
?>  

Další informace o této konverzi viz mauál Unix, funkce strtod(3).

Zajímavým problémem je ověření, zda předané jméno a heslo jsou správné. Asi je třeba se podívat do tabulky zákazníků - řekněme, že se jmenuje "zakaznici" a má sloupečky "login", "pwd", "id" (int, auto increment, primary key) a případně další, které nás teď nezajímají; hodnoty máme předané v $_POST["user"]a $_POST["pwd"], takže můžeme prohledat tabulku SQL příkazem SELECT:

SELECT id FROM zakaznici WHERE login=$_POST['user'] AND pwd=$_POST['pwd'];

Předpokládám, že příkaz bude zadán mezi uvozovkami, a jména proměnných se tak nahradí hodnotou. Pokud dotaz vrátí jakýkoli řádek (MySQLFetchAssoc...), je to přímo id uživatele, který si právě objednává auto.

Skript tedy bude v zásadě stejný jako v prvním případě, jen červeně zapsané řádky nahradí několik různobarevných řádek, protože předáváme heslo, jak bylo právě popsáno, a také složítěji přejímáme proměnnou $id_a (viz výše):

<?php
mysql_connect('mysql.webzdarma.cz','zpp','tudlenudle')
 or die('chyba:'.mysql_error() );
mysql_select_db('zpp');

$result=mysql_query("SELECT id FROM zakaznici WHERE login=$_POST['user'] AND pwd=$_POST['pwd'];");
if ($result) {  //něco se vrátilo, teď jen jestli je to platný uživatel...
$row=mysql_fetch_assoc($result);
if ($row["id"]>0){  //identita overena 
$id_z=$row["id"];

$id_a = 0; //pro pripad, ze by se nenasel vysledek...
foreach ($_POST as $key => $value) {if (substr($key,0,3)=="id_") {$id_a = substr($key,3)}};
if ($id_a == 0) {
$result=mysql_query('INSERT INTO vypujcky VALUES ("'.$id_z.'", "'.$id_a.'", CURDATE());');
$result=mysql_query('UPDATE auta SET komu="'.$id_z.'" WHERE id="'.$id_a.'";');

} else {echo "nepovedlo se dekodovat promennou s predanym id auta (spatne odladeno)";};
};}
mysql_close(); 

?>

Poznámka. Data musíme vkládat opatrně, nebo je "přechroustat" funkcí mysql_real_escape_string, aby uživatel nemohl zmást server vložením dat do databáze, které obsahují například apostrofy a podobně. Není nutné zde, auta do databáze vkládá správce aplikace, který si může dát pozor; horší to bude u registrace nového uživatele. Lépe je ovšem podobné podezřelé znaky v login name, password, e-mailu a podobně zakázat - mohly by komplikovat každý výpis.