Problémy aplikace On-line testů a jejich řešení Autor: Ing. Lukáš Trombik Vydalo Gymnázium Františka Živného v rámci projektu číslo 0560P 2005
Uvedení do problematiky Tvorba aplikace On-line testu se sebou nese i spoustu úskalí, s kterými je potřeba počítat. Mám zde namysli ošetření dané aplikace, zejména formulářů. Ty, mimo bezesporých výhod, v sobě skrývají i spoustu nešvaru, které je potřeba ošetřit a docílit toho, že IS On-line testů bude ukazovat vždy korektní výsledky, které odpovídají znalostem daného uživatele. Nebudu zde popisovat práci s formuláři jako takovými a jejich následné ověření. Vše je popsáno na řadě veřejných serverů, které se věnují tvorbě www stránek. Omezím se výhradně na ošetření výsledného skriptu, tj. formuláře jenž zobrazuje náhodně vygenerované otázky a po jeho odeslání se danému uživateli zobrazí výsledná statistika. Hlavním problémem těchto aplikací je možnost, po zodpovězení daných otázek a následném vyhodnocení, vrátit se zpět do výchozího stavu a dané otázky poopravit a znovu vyhodnotit. Tím daný uživatel může vylepšit své celkové skóre a danou statistiku. Tento problém není řešen takřka na žádném webu, který se věnuje on-line aplikacím! Na druhou stranu je třeba říci, že ani mé řešení není stoprocentní, jen snižuje pravděpodobnost podvodu. Pro lepší pochopení zde přikládám ukázku daného problému. 1. Výchozí stav bezprostředně po vygenerování otázek.
2. Stav po zodpovězení otázek. Pro ilustraci jsem úmyslně zadal u všech otázek špatné odpovědi. 3. Stav, kdy jsem poopravil již vygenerované a vyhodnocené otázky a dal znovu vyhodnotit.
Řešení daných problémů 1. Odfiltrování tlačítka Vyhodnotit Pokud vyhodnocení na dané otázky provádíte ve stejném skriptu, na stejné stránce, na které rovněž zobrazujete vygenerované otázky, je potřeba zabránit opětovnému stisku odesílacího tlačítka formuláře. Jednou z možnosti je skrytí, přesněji zneviditelnění tohoto tlačítka ihned po jeho stisknutí nebo při vyhodnocení. Stačí nastavit danému tlačítku vlastnost visibility, která určuje zda daný prvek bude viditelný či nikoliv. <input type="submit" id="odeslat" class="odeslat" value="vyhodnotit"> <style type="text/css" media="all">.odeslat {visibility:hidden; </style> Nevýhody: například v prohlížeči Opera můžeme vypnout kaskádové styly. 2. Odfiltrování pravého tlačítka myši Jednou z možností, jak zabránit alespoň úzké skupině uživatelů, vrátit se k výchozímu stavu a dané otázky znovu poopravit je odfiltrování pravého tlačítka myši. Tím zakážeme i možnost používat místní nabídky v dané aplikaci. Nejlepší možnost, jak toho dosáhnout je přidat skript pro filtraci jako atribut či vlastnost těla dané stránky. Například tímto způsobem: <body onmousedown="if((event.button == 2) (event.button==3)) alert('nepovolená operace!')"> Další možností je tento skript: <script language="javascript"> <!-- var message="nepovolená operace!"; function clickie4(){ if (event.button==2){ alert(message);
return false; function clickns4(e){ if (document.layers document.getelementbyid&&!document.all){if (e.which==2 e.which==3){alert(message);return false; if (document.layers){ document.captureevents(event.mousedown); document.onmousedown=clickns4; else if (document.all&&!document.getelementbyid){ document.onmousedown=clickie4; document.oncontextmenu=new Function("alert(message);return false;") // --> </script> Oba výše uvedené způsoby řešení jsou totožné a vedou ke stejnému cílu. Druhy zmiňovaný je o něco preciznější s ohledem na různé variace prohlížečů. Výsledek: Nevýhody: uživatel může mít zakázané spouštění jazyka Javascript.
3. Přesměrování koncových otázek do nového okna, nové stránky Další možností, jak je možné snadno se vrátit se do předešlého stavu, je použít navigační lištu v daném prohlížeči. Proto se nabízí možnost přesměrovat vygenerované otázky do nového okna, na které budou uplatněna určitá omezení - restrikce. Novému oknu zakážeme určité volby, hlavně výše uvedenou navigační lištu. Restrikce uplatněny pro nové okno: toolbar=no (označuje panel nástrojů - zpět, vpřed, atd.) location=no (vstupní pole adresy) menubar=no (nabídka soubor, úpravy, atd.) directories=no (speciální panel odkazů) Další vlastnosti se týkají především umístění okna a jeho velikosti. Například volby: scrollbars=yes, resizable=yes, status=yes, top=0, left=0,... Výsledek: Okno bez navigační lišty a hlavního menu.
4. Ošetření klávesy backspace I přes všechna vylepšení, existuje jednoduchý recept, jak se vrátit do předešlého stavu, tím je klávesa backspace. Ta umí jednak vymazat znak před kurzorem a ve formulářích plní funkci návratu do předešlého stavu. Kdyby se jednalo o jakýkoliv jiný znak či snad číslo, bylo by možné jej snadno odfiltrovat. Při každém stisku klávesy se nám totiž generuje kód, podle kterého poznáme, která klávesa byla stisknuta. Viz například tento skript, kterým snadno odfiltrujeme čísla. function IsDigit(c) { return ((c >= 48) && (c <= 57)); function IsSpecial(c){ return (((c >= 0) && (c <= 31)) (c == 46) ); function checkonlynumber(e) { var code; if (!e) var e = window.event; if (e.keycode) code = e.keycode; else if (e.which) code = e.which; if (!((IsDigit(code)) (IsSpecial(code)))) { e.returnvalue = false; return false; e.returnvalue = true; return true; <input type="text" name ="cislo" onkeypress="return checkonlynumber(event)" /> U klávesy backspace tomu tak není a není ji možné tímto způsobem odchytit. Takže danou klávesu musíme nechat dál plnit její činnost a je třeba postupovat jinak. Existuje zde více řešení, která vedou k ošetření daného problému. Já zvolil práci se session proměnnými. Nebudu se zde příliš rozepisovat, jak se s takovými superglobálními proměnnými pracuje. Vysvětlení se spoustou řešení je na webu. Jen zde zdůrazním vlastnosti, které v sobě session nesou. Vlastnosti: každému novému uživateli se přiřadí unikátní identifikátor (tzv. session-id) o předává se s každým požadavkem pomocí cookie nebo parametrů v URL, resp. skrytých polí ve formuláři o session-id je konstruováno tak, aby bylo těžko odhadnutelné (většinou náhodné číslo + hashovací funkce MD5 nebo SHA) pro každé session-id má webový server vyhrazen prostor pro ukládání dat (proměnných) o sdílená paměť o soubory o databáze S daných vlastností vyplývá, že běžné globální proměnné jsou platné jen během jednoho klientského dotazu, jednoho běhu skriptu, poté se jejich hodnota nenávratně ztrácí. Zatímco
session proměnné byly implementovány tak, že uchovávají svou hodnotu napříč různými dotazy uživatele po celou dobu existence příslušné session. Session proměnnou může být jakákoliv globální proměnná, kterou programátor zaregistruje do aktuální session. Systém sám na počátku zpracování každého dalšího dotazu obnoví její hodnotu a stejně tak na konci zpracování ji opět uloží. Práce se session je i celkem jednoduchá. Bezprostředně po vyhodnocení daného testu si zaregistruji a nastavím danou session. session_start(); $_SESSION['vyplneno'] = 1; Při dalším vyhodnocení si překontroluji jestli už daná session proměnná není nastavena a pokud ano vypíšu hlášku a znepřístupním test. if($_session['vyplneno'] == 1){ echo 'Tento test jste již vyplnil'; exit; Do rodičovské stránky, tj. stránky, kde vybírám počet otázek ještě před samotným nalosováním otázek, vložím následující kód, kterým uvolním danou session. session_start(); if (isset($_session['vyplneno'])) { unset($_session['vyplneno']); Tím bych měl vyřešen problém s klávesou backspace, případně s jiným pokusem o návrat do již zodpovězeného testu, pokud bych počítal s tím, že uživatel si nebude chtít daný test zopakovat. Problém však může nastat, pokud se u jednoho počítače střídá více uživatelů nebo si daný uživatel chce stejný test, byť s jinými otázkami opětovně udělat. Session proměnné, jak už jsem poznamenal, uchovávají svou hodnotu napříč různými dotazy uživatele po celou dobu existence příslušné session, tzn. pokud ji sami nezrušíme, tak je platná po celou dobu, kdy pracujeme s daným prohlížečem. Museli bychom tak, zavřít okno prohlížeče a znovu jej otevřít, tím se nám zaregistruje nová session s jiným identifikátorem. Že se o to postará uživatel, na to spoléhat nelze. Musíme se o to postarat sami. Řešení není nikterak složité. Postačí, když si vytvoříme pomocnou proměnnou, která bude vždy nabývat jiné hodnoty a bude platná jen v koncovém okně s vygenerovanými otázkami, tzn. při opětovném výběru daného testu se nám proměnná a tím i daná session naplní vždy novou - různou hodnotou. V rodičovské stránce, tj. stránce, kde vybírám počet otázek vytvořím proměnnou, která bude nabývat vždy náhodných hodnot user=user+math.random() (například user19, user1250,...) Bezprostředně po vyhodnocení daného testu si zaregistruji a nastavím danou session na hodnotu pomocné proměnné, tj. například user19, user1250, atd. session_start(); $_SESSION['vyplneno'] = $user;
Při dalším vyhodnocení si překontroluji jestli už daná session proměnná není nastavena a pokud ano vypíši hlášku a znepřístupním test. session_start(); if($_session['vyplneno'] == $user){ echo 'Tento test jste již vyplnil'; exit; Pomocná proměnná je vždy platná jen v koncovém okně a pokud si například daný test chceme zopakovat, tak se nám hodnota proměnné přepíše vždy novou hodnotou a zaregistrovaná globální proměnná - session nám zanikne se zavřením okna prohlížeče. Takže nemusíme ručně nikde nic promazávat, tj. výhoda oproti variantě ukládat nějaké pomocné hodnoty do databáze či textového souboru, kde bychom dodatečné promazávání museli řešit. Výsledek: Závěr Jak už jsem v úvodu uvedl plnohodnotné vyřešení daného problému není. Je to jako mnohokrát řešený problém se zamezením vícenásobného hlasování v nějaké anketě. Stoprocentně to vyřešit nelze, jen je možné výše uvedenými či dalšími způsoby snížit pravděpodobnost, že se to někomu povede obejít.