HØGSKOLEN I SØR-TRØNDELAG Avdeling for informatikk og e-læring - AITeL Kandidatnr: Eksamensdato: 15. desember 2004 Varighet: Fagnummer: Fagnavn: Klasse(r): 3 timer LV197D Webprogrammering med PHP FU Studiepoeng: 6 Faglærer(e): Svend Andreas Horgen tlf: 73 55 92 69 Hjelpemidler: Oppgavesettet består av: Alle skriftlige hjelpemidler Forsiden, 1 oppgave på 2 sider og to vedlegg på til sammen 3 sider. Totalt 6 sider i eksamenssettet. Viktig: Les hele oppgaveteksten før du setter i gang. Planlegg tiden godt. Hvis du føler det blir vanskelig å skrive kode, er det bedre å skissere logikken med pseudokode eller egne ord enn ikke å gjøre noe. Lykke til! Side 1 av 11
Oppgave Spørrekonkurranse (100%) Du skal lage en spørrekonkurranse for det fiktive nettstedet www.hoppuka.no. Her er noen kjennetegn: Konkurransen skal ha 5 spørsmål knyttet til hoppsport, med fire alternativer for hvert spørsmål. Etter å ha svart på siste spørsmål skal resultatene summeres opp. Bare de som består konkurransen skal kunne registrere seg. Blant de registrerte trekkes en vinner av en tur til hoppuka 2005. Det er mange måter å lage konkurranser på rent teknisk sett. I dette tilfellet har allerede en grafisk designer laget 5 HTML-sider, der hver side har et hardkodet spørsmål og fire alternativer, samt én svar-knapp. HTML-koden for en tilfeldig valgt side ser slik ut: <strong>hvem vant kvinnenes tysk-østeriske hoppuke 2004?</strong> <form action="" method="get"> <input type="radio" name="spm" value="anette Sagen"> Anette Sagen<br> <input type="radio" name="spm" value="lindsay Van"> Lindsay Van<br> <input type="radio" name="spm" value="line Jahr"> Line Jahr<br> <input type="radio" name="spm" value="henriette Smedby"> Henriette Smedby<p> <input type="submit" value="svar" name="knapp"> </form> Du kan gjøre deloppgavene sammen eller hver for seg. Det er uansett lurt å lese alle deloppgavene før du starter med besvarelsen din. Planlegg tiden godt! Det er ikke gitt at hver deloppgave teller like mye. Du ser at del-oppgavene bygger på hverandre. Dersom det er noen deloppgaver du ikke får til, kan du likevel gjøre de andre oppgavene. Få i så fall frem (med tekst) de antakelser du må gjøre, for eksempel hvor data kommer fra, hvordan de lagres midlertidig og liknende. Vedlegg A har skjermbilder med spørsmålene i konkurransen og riktige svar. Du trenger ikke å skrive inn all teksten i løsningen din, men det er tatt med for å vise hvordan systemet er tenkt å fungere. Vedlegg B har skjermbildene som skal vises i forbindelse med oppsummeringen. Side 2 av 11
a) Hvilken form for tilstandsbevaring vil du bruke i denne løsningen? Begrunn svaret. Svar: Sessions er best, fordi det sikrer at alle kan ta konkurransen. Cookies kan være avslått. URL går også an, men er tungvindt, særlig hvis konkurransen har mer enn 5 spørsmål. Sikkerheten er ikke noe argument her, fordi det ikke er sensitive data som evt. lagres på klienten (ved valg av cookies). Altså er det best å gjøre denne oppgaven med sessions eller cookies. MERK: Det er ikke lett å få til hidden, fordi da må du inn med hidden-felter i <form> og litt av poenget er at en IKKE skal forandre på de statiske HTML-filene. Med et JavaScript går det an å trikse slike inn dynamisk, men det er ikke lurt tatt i betraktning den fine muligheten for å bruke sessions. Det er både enklere og mer effektivt, samt sikrere! b) Siden den grafiske designeren allerede har laget spørsmålene og definert utseendet, blir din jobb å programmere det som mangler for at systemet skal kunne registrere svarene på en korrekt måte. Legg merke til at action-attributtet er satt tomt, dermed vil samme side kalles opp ved klikk på knappen. Neste figur viser et eksempel på hva som vises etter at to spørsmål er besvarte. Merk at toppteksten Dette er spørsmål X av 5 ikke er hardkodet i noen av HTML-filene, så det må du programmere i løsningen din. Hint: Tenk i retning av inkludering. Du kan for enkelhetsskyld anta at brukeren oppfører seg eksemplarisk og ikke trykker på back-knappen i nettleseren. Svar: Det er flere måter å gjøre dette på, noen er mer dynamiske enn andre. Det beste er likevel å la HTML-filene ha kun HTML i seg, slik at spåørsmålene kan lages av den grafiske designeren alene. Dermed er det lurt at du som programmerer lager en side som tar seg av logikken, og inkluderer siden med riktige spørsmål. Kommentar til koden, som gjelder for både oppgave b og c: Legger brukerens svar i en rekke SESSION-variabler. Kan ikke være numeriske, så lager dem med tekstlig prefiks og nummer bak. Legger fasiten i en global matrise som heter fasiten. Denne har samme nøkler som tekstlig prefiks i session-variablene. En session-teller holder orden på hvor langt vi er kommet i konkurransen Så lenge telleren er mindre enn 6 vil neste spørsmålsfil inkluderes. For å få dette lettest til er filnavnene på formen sporsmaal_1.php, sporsmaal_2.php Side 3 av 11
Oppsummeringen innebærer å gå gjennom fasiten og sammenlikne med tilhørende session-variabel, identifisert med fasit-nøkkelen siden de to er like (som forklart i punkt 1 og 2). Kunne lagd funksjoner for å sjekke antall riktige og lage tabellen, men velger å gjøre alt i en løkke fordi det er så lite kode som skal til. Dette er heller ikke noen ultimat fasit, men et forslag til løsning. Registrerer også at konkurransen er ferdig. Brukes på utfyllingssiden. Side 4 av 11
<?php session_start(); $fasiten = array("nummer_1" => "Bjørn Wirkola", "nummer_2" => "Finland", "nummer_3" => "Anette Sagen", "nummer_4" => "Oberstdorf", "nummer_5" => "Sepp Bradl"); //første gang nullstilles teller if (!isset($_session['teller'])) { $_SESSION['teller'] = 1; //Skal svaret behandles? if (isset($_get['spm'])) { //fang opp svaret if ($_SESSION['teller'] <=5 ) { $nummer = "nummer_". $_SESSION['teller']; $_SESSION[$nummer] = $_GET['spm']; //hvor langt er vi kommet? Oppdater telleren $_SESSION['teller'] ++; //skjer bare hvis ikke ferdig //spørsmål if ($_SESSION['teller']<=5){ //Vis neste skjema echo "<h3>dette er spørsmål nr {$_SESSION['teller'] av 5</h3>"; include "sporsmaal_". $_SESSION['teller']. ".php"; else { //vis oppsummering echo "<table border='1'>"; echo "<tr><th>spørsmål</th><th>ditt svar</th><th>korrekt?<th></tr>"; $antallriktig = 0; $teller = 1; foreach ($fasiten as $nokkel => $riktigsvar) { echo "<tr><td>$teller</td>"; $teller ++; echo "<td>". $_SESSION[$nokkel]. "</td>"; if ($_SESSION[$nokkel] == $riktigsvar) { $antallriktig ++; echo "<td>riktig</td>"; else { echo "<td>feil</td>"; echo "</tr>"; echo "</table>"; if ($antallriktig >= 3){ echo "Godkjent! Du kan nå <a href='trekning.php'> registrere deg og bli med i trekningen</a> om fine premier. "; $_SESSION['ferdig'] = true; //registrerer at man har klart konkurransen, brukes på oppsummeringssiden Side 5 av 11
else { echo "Du fikk ikke nok riktige. <a href='index.php?null=fjkd'>prøv igjen...</a>"; //slutt med å vise oppsummeringen //debug ved behov... //echo "<pre>"; //print_r($_session);?> c) Skriv kode som oppsummerer resultatet etter at alle spørsmålene er besvarte. Se vedlegg B for tips til hvordan oppsummeringen kan se ut. Hvis det er ingen, en eller to feil, skal en lenke til en side med registrering vises. Ved flere feil blir brukeren tilbudt å prøve på nytt igjen, og får ikke frem registreringslenken. Svar: Se oppgave b. Oppgave b og c bør telle en del til sammen, for det er utfordrende å lage koden og pønske ut en smart måte å gjøre det på. Det fins flere veier til Rom det viktige er at løsningen er lagd slik at den kan fungere, men A- og B-kandidatene vil trolig få til inkludering. Oppsummering med hardkoding av alternativene (tekstlig sammenlikning av svarene) er ikke fleksibelt, og ved 100 spørsmål blir det totalt uoversiktlig. Det bør likevel gi noe uttelling å tenke slik. d) Skisser et skjema (enten med HTML-kode eller med tegning der du navngir feltene) som kan vises til de som klarer konkurransen slik at navn, telefonnummer og e-postadresse kan fylles inn. Disse opplysningene skal lagres i en database. Skriv koden for dette. Valider inngangsdatane slik at e-postadresse må ha krøllalfa, telefonnummer må bestå av 8 sifre, og navnet må ha innhold. Svar: Dette kan virke omfattende, men det er prinsippet som er viktigst: At de validerer data riktig. Regulære uttrykk kan brukes, men er egentlig litt overkill her. <?php session_start(); //unngår at noen besøker siden og jukser seg til seier. if (!isset($_session['ferdig'])) { die("du har ikke gjort konkurransen på lovlig vis..."); //sjekker om e-post har alfa, telefon har 8 sifre og navn er satt. //returnerer feilmelding(er) eller ingenting function ValiderData() { $beskjed = ""; if (!strstr($_post['epost'], "@")) { $beskjed.= "E-post mangler snabel-a (dansk)<br>"; //gjenta dette for også e-post og telefon if (!isset($_post['navn']) empty($_post['navn']) ) { $beskjed.= "Navn er ikke utfylt<br>"; if (!is_numeric($_post['telefon'])) { $beskjed.= "Telefonnummer kan bare bestå av sifre<br>"; if (strlen($_post['telefon']) > 8) { Side 6 av 11
$beskjed.= "Telefonnummer skal ikke ha mer enn 8 sifre"; return $beskjed; //kan være tom, i så fall går alt bra //legg inn i database if (isset ($_POST['knapp'])){ $feil = ValiderData(); //enten if ($feil == ""){ $conn = mysql_connect("localhost", "bruker", "passord"); mysql_select_db("databasenavn", $conn); $sql = "INSERT INTO tabell VALUES('". $_POST['navn']. "', '". $_POST['epost']. "', '". $_POST['telefon']. "'"; //echo $sql; mysql_query($sql, $conn); echo "Resultatet er nå lagret. Tilbake"; //legge inn i database else{ //vis feilmelding echo "<strong>følgende feil oppstod:</strong><p>$feil"; echo "<a href='javascript:history.go(-1)'>tilbake</a>"; else {?> <h1>fyll inn din adresse</h1> <form action="" method="post"> Navn: <input type="text" name="navn"> <br> E-post: <input type="text" name="epost"> <br> Telefon: <input type="text" name="telefon"> <br> <input type="submit" value="registrer opplysninger i database" name="knapp"> </form>?> <?php //slutt else, vise skjema e) Som du ser av skjermbildene i vedlegg B, må brukeren klikke på en lenke for å få registrere seg. Det betyr at noen kan skrive inn adressen til registreringsskjemaet direkte og slik registrere seg uten å ta konkurransen. Hva kan gjøres rent sikkerhetsmessig for å unngå dette? Svar: Enten slik som gjort i oppgave b, d med registrering av godkjent test vha variabelen _SESSION['ferdig']; Kunne også ha brukt et passord i lenken, men det er ikke særlig smart, for da kan lenken distribueres. Merk: Det vil ikke fungere med.htaccess her det vil være galt svar. f) I dette tilfellet har en grafisk designer hardkodet spørsmålene. Det gjør det tungvindt å legge til nye spørsmål, og det gjør løsningen mindre dynamisk. Ser du for deg noen alternative løsninger som kan gi mer fleksibilitet? Forklar og tegn opp hvis du trenger det. Side 7 av 11
Svar: Mange muligheter her. En enkel måte er å hardkode spørsmålene og svarene i en matrise, og så lage logikk for å vise neste spørsmål. Det blir rett og slett å hente ut informasjon fra neste matriseelement. Fordelen med en slik løsning er at den er skalerbar det er bare å legge til nye spørsmål og svar i matrisen, og dermed øker konkurransen i omfang. Alt kan dessuten ligge i ett og samme script, uten at det blir noe særlig større enn det som er vist i oppgave b/c. Oppsummeringen blir uansett den samme. Database/fil: Lagre spørsmålene i database eller på fil. Samme logikk som med matrise, men kan da lettere bruke spørsmålene i flere sammenhenger. Sikkert andre muligheter også! Side 8 av 11
Vedlegg A Her er noen skjermbilder som viser alle spørsmål med riktig svar avkrysset. Den grafiske designeren har laget alt utenom toppteksten Dette er spørsmål nr X av 5. Side 9 av 11
Side 10 av 11
Vedlegg B Oppsummeringen vises uansett, men bare når det er nok riktige svar vil brukeren få gå til siden for registrering. Her er et eksempel på en bruker som har svart riktig på alle spørsmålene, og får frem lenke til registrering: Eksempel på en bruker som ikke har tilstrekkelig riktige svar, og må ta konkurransen på nytt: Side 11 av 11