Zpracování chyb z formuláře

15.10.2001 20:49 | blackhole

Prakticky každý, kdo pracuje s PHP se už jistě někdy setkal s odesíláním dat skrze formuláře. A také určitě nesmi spoléhat na dobrou vůli uživatelů a ošetřit případné chyby, kterých se uživatelé při vkládání dopustí. A právě tomu bych se chtěl věnovat v tomto článku.
Předpokládejme, že chceme, aby se nám uživatel zaregistroval do systému; k tomu mu (dejme tomu) stačí zadat přezdívku, e-mail a heslo: <TABLE>
<FORM action=\"pridejuzivatele2.php\" method=\"post\">
<TR>
<TD>Přezdívka: </TD><TD><INPUT type=\"text\" name=\"nick\" value=\"<? echo $nick; ?>\"></TD>
</TR>
<TR>
<TD>E-mail: </TD><TD><INPUT type=\"text\" name=\"email\" value=\"<? echo $email; ?>\"></TD>
</TR>
<TR>
<TD>Heslo: </TD><TD><INPUT type=\"password\" name=\"heslo\"></TD>
</TR>
<TR>
<TD>Kontrola hesla: </TD><TD><INPUT type=\"password\" name=\"heslo2\"></TD>
</TR>
<TR>
<TD colspan=\"2\"><INPUT type=\"submit\" value=\"Přihlaš!\"></TD>
</TR>
</FORM>
</TABLE>Dobrá. Nyní předpokládejme, že uživatel udělá chybu (dvě, tři)….jak mu to dát vědět?
Varianta první: If…die
První a nejnešťastnější metodou, k jaké se začátečníci uchylují (ano, i já jsem to dělal) je metoda vyhodnotím_podmínku->nesplněna->ukončím běh skriptu.
Nejprve si však ukažme příkaz pro vytvoření tabulky: CREATE TABLE uzivatele(
id int auto_increment not null,
nick char(15) not null,
email char(25) not null,
heslo char(30) not null,
primary key(id)
);...a soubor function.php s funkcemi, které budeme potřebovat: <?

function spojeni()
{
if (!$spojeni = MySQL_Connect(\"localhost\", \"databaze\", \"\")){
echo \"Nepodařilo se připojit k databázi!\";
die;
}
if (!$select = MySQL_Select_Db(\"databaze\")){
echo \"Chyba vybírání databáze! \";
die;
}
$polepripojeni[0]=$spojeni;
$polepripojeni[1]=$select;
return $polepripojeni;
}

function kontrola_mailu($email)
{
if (EregI(\"^[a-z0-9]+[a-z0-9\\._-]*[a-z0-9]+@[a-z0-9]+[a-z0-9\\._-]*[a-z0-9]+\\.[a-z]{2,3}$\", $email) || EregI(\"\\.{2,}\", $email) || EregI(\"_{2,}\", $email) || EregI(\"-{2,}\", $email))

{
return 1;
}

else{
return 0;
}
}

function upravretezec($retezec);
{
$retezec=addslashes($retezec);
$retezec=HTMLEntities($retezec);
$retezec=trim($retezec);
return $retezec;
}

?>A nyní "ukázkový" kód skriptu pridejuzivatele.php:<?

Header(\"Expires: \".GMDate(\"D, d M Y H:i:s\").\" GMT\"); // neukladat do cache
require \"./function.php\"; // připojíme funkce

$email=upravretezec($email);
$nick=upravretezec($nick);
$heslo=upravretezec($heslo);
$heslo2=upravretezec($heslo2);

If($email==\"\"){
echo \"Prosím zadejte vaši e-mailovou adresu! \";
die;
}

If($nick==\"\"){
echo \"Prosím zadejte vaši přezdívku! \";
die;
}

If($heslo==\"\"){
echo \"Prosím zadejte vaše heslo! \";
die;
}

If(!(kontrola_mailu($email)))
{
echo \"Vaše e-mailová adresa je v nesprávném tvaru!\";
die;
}

If($heslo!=$heslo2){
echo \"Heslo a kontrola hesla si neodpovídají! \";
die;
}
If(strlen($heslo)>30){
echo \"Vaše heslo je příliš dlouhé (delší než 30 znaků)! \";
die;
}
If(strlen($nick)>15){
echo \"Vaše přezdívka je příliš dlouhá (delší než 15 znaků)! \";
die;
}

If(strlen($email)>25){
echo \"Vás e-mail je příliš dlouhý (delší než 25 znaků)! \";
die;
}

spojeni();

$dotaz=\"INSERT INTO uzivatele(nick, email, heslo) VALUES('$nick', '$email', '$heslo')\";
$prikaz=MySQL_Query($dotaz);

If(!$prikaz){
echo \"Chyba při vkládání údajů do databáze! \";
die;
}
Else {
echo \"Byl jste úspěšně přidán! Děkujeme vám za vaši registraci.\";
die;
}
?>Dobrá. Takže dejme tomu, že uživatel zadá špatnou e-mailovou adresu A ZÁROVEŇ přiliš dlouhé heslo. Co se stane? Uvidí hlášku "Vaše e-mailová adresa je v nesprávném tvaru." Budiž, klikne na "Zpět" a zjistí, že musí všechny údaje vyplnit znova. Trošku ho to zaskočí, ale o registraci stojí, vyplní formulář znovu a...e-mailová adresa je tentokrát v pořádku, ale zase je dlouhé heslo...tak znovu... Možná se vám to zdá banální (a u formuláře takovéhoto rozsahu to také banální je), ale pokud využíváte delší formuláře (například třeba o 15 polích), můžete proklikat celé odpoledne. Jak z toho ven?
Varianta druhá: spojování řetězců
Zde vycházíme z myšlenky, že vytvoříme proměnnou, která bude kontrolovat, jestli jsou údaje správně zadány. Pokud ano, vložíme je do databáze, pokud ne, vypíšeme řetězce: <?
Header(\"Expires: \".GMDate(\"D, d M Y H:i:s\").\" GMT\");
require \"./function.php\";
$dataok=1;

$email=upravretezec($email);
$nick=upravretezec($nick);
$heslo=upravretezec($heslo);
$heslo2=upravretezec($heslo2);

If($email==\"\"){
$chyba1 = \"Prosím zadejte vaši e-mailovou adresu! \";
$dataok=0;
}

If($nick==\"\"){
$chyba2 = \"Prosím zadejte vaši přezdívku! \";
$dataok=0;
}

If($heslo==\"\"){
$chyba3 = \"Prosím zadejte vaše heslo! \";
$dataok=0;
}

If(!kontrola_mailu($email){
$chyba4 = \"Vaše e-mailová adresa je v nesprávném tvaru!\";
$dataok=0;
}

If($heslo!=$heslo2){
$chyba5 = \"Heslo a kontrola hesla si neodpovídají! \";
$dataok=0;
}

If(strlen($heslo)>30){
$chyba6 = \"Vaše heslo je příliš dlouhé (delší než 30 znaků)! \";
$dataok=0;
}

If(strlen($nick)>15){
$chyba7 = \"Vaše přezdívka je příliš dlouhá (delší než 15 znaků)! \";
$dataok=0;
}
If(!(EregI(\"[a-zA-Z_0-9]\", $nick)){
$chyba8 = \"Vaše přezdívka může obsahovat pouze písmena, číslice a podtržítko! \";
$dataok=0;
}

If(strlen($email)>25){
$chyba9 = \"Váš e-mail je příliš dlouhý (delší než 25 znaků)! \";
$dataok=0;
}

If($dataok==1){
spojeni();
$dotaz=\"INSERT INTO uzivatele(nick, email, heslo) VALUES('$nick', '$email', '$heslo')\";
$prikaz=MySQL_Query($dotaz);

If(!$prikaz){
echo \"Chyba při vkládání údajů do databáze! \";
die;
}
Else {
echo \"Byl jste úspěšně přidán! Děkujeme vám za vaši registraci.\";
die;
}
}

Else{
echo $chyba1;
echo \"<BR />\".$chyba2;
echo \"<BR />\".$chyba3;
echo \"<BR />\".$chyba4;
echo \"<BR />\".$chyba5;
echo \"<BR />\".$chyba6;
echo \"<BR />\".$chyba7;
echo \"<BR />\".$chyba8;
echo \"<BR />\".$chyba9;

}
?>Nevýhody tohoto postupu jsou zřejmé: co když uživatel udělá, dejme tomu, <EM>jen</EM> 1. a 4. chybu? Budou mezi tím 2 prázdné řádky...což nevypadá dobře. Ukažme si tedy variantu poslední.
Varianta třetí: ukládání do polí
Zde využijeme jedné vlastnosti polí: pokud neinicializujeme pole s určitou hodnotou, pak se samo zinicializuje s hodnotou o jedna vyšší, než je poslední hodnota pole, popř. z nulou:<?
Header(\"Expires: \".GMDate(\"D, d M Y H:i:s\").\" GMT\");
require \"./function.php\";

$email=upravretezec($email);
$nick=upravretezec($nick);
$heslo=upravretezec($heslo);
$heslo2=upravretezec($heslo2);

$dataok=1;

If($email==\"\"){
$chyba[] = \"Prosím zadejte vaši e-mailovou adresu! \";
$dataok=0;
}

If($nick==\"\"){
$chyba[] = \"Prosím zadejte vaši přezdívku! \";
$dataok=0;
}

If($heslo==\"\"){
$chyba[] = \"Prosím zadejte vaše heslo! \";
$dataok=0;
}

If(!kontrola_mailu($email){
$chyba[] = \"Vaše e-mailová adresa je v nesprávném tvaru!\";
$dataok=0;
}

If($heslo!=$heslo2){
$chyba[] = \"Heslo a kontrola hesla si neodpovídají! \";
$dataok=0;
}

If(strlen($heslo)>30){
$chyba[] = \"Vaše heslo je příliš dlouhé (delší než 30 znaků)! \";
$dataok=0;
}

If(strlen($nick)>15){
$chyba[] = \"Vaše přezdívka je příliš dlouhá (delší než 15 znaků)! \";
$dataok=0;
}
If(!(EregI(\"[a-zA-Z_0-9]\", $nick)){
$chyba[] = \"Vaše přezdívka může obsahovat pouze písmena, číslice a podtržítko! \";
$dataok=0;
}

If(strlen($email)>25){
$chyba[] = \"Váš e-mail je příliš dlouhý (delší než 25 znaků)! \";
$dataok=0;
}

If($dataok==1){
spojeni();
$dotaz=\"INSERT INTO uzivatele(nick, email, heslo) VALUES('$nick', '$email', '$heslo')\";
$prikaz=MySQL_Query($dotaz);

If(!$prikaz){
echo \"Chyba při vkládání údajů do databáze! \";
die;
}
Else {
echo \"Byl jste úspěšně přidán! Děkujeme vám za vaši registraci.\";
die;
}
}

Else{
$pocet_iretaci=count($chyba);
--$pocet_iretaci; // POZOR, na toto se často zapomíná: count() vrací počet hodnot v poli, ale my máme pole od 0

for($idx=0; $idx<$pocet_iretaci; ++$idx){
echo \"Při odesílání formuláře vznilkly následující chyby: <BR />\";
echo $chyba[$idx].\"<BR />\";
}
}
?>Tímto způsobem dáte uživateli vědět o všech chybách najednou. Místo polí by ještě šli použít řetězce spojované pomocí .= , ale z vlastní zkušenosti mohu říct, ze s poli se lépe pracuje, pokud např. chcete jednotlivé položky od sebe oddělit čarou. Ovšem jedna věc tu ještě chybí: pokud uživatel udělá chybu a klikne na "Zpět" v prohlížeči, zobrazí se mu prázdný formulář...upravme proto forcyklus: <?
for($idx=0; $idx<$pocet_iretaci; ++$idx){
echo \"Při odesílání formuláře vznilkly následující chyby: <BR />\";
echo $chyba[$idx].\"<BR />\";
echo \"<FORM action=\\\"uvodnistranka.php\\\">\";
echo \"<INPUT type=\\\"hidden\\\" name=\\\"nick\\\" value=\\\"\".$nick.\"\\\">\";
echo \"<INPUT type=\\\"hidden\\\" name=\\\"email\\\" value=\\\"\".$email.\"\\\">\";
// heslo z bezpečnostních důvodů předávat nebudeme
echo \"<INPUT type=\\\"submit\\\" value=\\\"Zpět\\\">\";
}
?>...a úvodní stránku na <TABLE>
<FORM action=\"pridejuzivatele.php\" method=\"post\">
<TR>
<TD>Přezdívka: </TD><TD><INPUT type=\"text\" name=\"nick\" value=\"<? echo $nick; ?>\"></TD>
</TR>
<TR>
<TD>E-mail: </TD><TD><INPUT type=\"text\" name=\"email\" value=\"<? echo $email; ?>\"></TD>
</TR>
<TR>
<TD>Heslo: </TD><TD><INPUT type=\"text\" name=\"heslo\"></TD>
</TR>
<TR>
<TD>Kontrola hesla: </TD><TD><INPUT type=\"text\" name=\"heslo2\"></TD>
</TR>
<TR>
<TD colspan=\"2\"><INPUT type=\"submit\" value=\"Přihlaš!\"></TD>
</TR>
</FORM>
</TABLE> Almad