HØGSKOLEN I SØR-TRØNDELAG Avdeling for informatikk og e-læring - AITeL Kandidatnr: Eksamensdato: 20. mai 2005 Varighet: 3 timer (09:00 12:00) Fagnummer: Fagnavn: Klasse(r): LV197D Webprogrammering med PHP FU Studiepoeng: 6 Faglærer(e): Svend Andreas Horgen tlf: 73 55 92 69 Kurskonsulent Siri Wæhre Lien (tlf. 73 55 91 54) Hjelpemidler: Oppgavesettet består av: Alle skrevne og trykte hjelpemidler tillatt Forsiden, 1 oppgave på 3 sider og 2 vedlegg. Totalt 7 sider i eksamenssettet. Vedlegg: 2 Planlegg tiden godt. Hvis du føler det blir vanskelig å skrive kode eller travelt, er det bedre å skissere logikken med pseudokode eller egne ord enn ikke å gjøre noe. Dersom noe virker uklart i oppgavene, må du selv gjøre de nødvendige antagelser og få med disse i besvarelsen. Vedlegg A har figurer fra løsningen du skal lage. Vedlegg B har nyttige SQL-spørringer som kan brukes. Lykke til! LØSNINGSFORSLAG Side 1 av 11
Oppgave Fotballweb (100%) Fotballaget ATL-Gunners har greid det kunststykket å kvalifisere seg for spill i toppdivisjonen. Gleden i laget er stor og de har nå planer om å lage et eget nettsted (http://www.atl-gunners.no/). Her skal lagets trofaste supportere kunne holde seg oppdatert om det som rører seg i klubben og bestille billetter til lagets hjemmekamper. For å hjelpe seg med utviklingen av nettstedet er du blitt engasjert som en del av prosjektgruppen. Nettstedet vil bestå av flere PHP-script, blant annet index.php, billetter.php og kvittering.php. Du skal i de påfølgende oppgavene programmere funksjonaliteten bak disse sidene som angitt i deloppgavene. a) Du skal i denne oppgaven lage filen index.php se Figur 3 i Vedlegg A, basert på følgende ønsker: Første gang siden lastes skal det vises en velkomsthilsen. En kommer til dette utgangspunktet dersom logoen klikkes. En nedtrekksliste lar brukeren velge ønsket informasjon som skal vises når Velg-knappen trykkes. Mulige valg er Nyheter, Laget, Trenerens hjørne og Kjøp billetter. For enkelhetsskyld kan du programmere slik at tilstanden ikke huskes (dvs. i nedtrekkslisten står det alltid Nyheter uavhengig av hva som er valgt tidligere. Hvis brukeren velger Nyheter skal innholdet i filen nyheter.html vises i stedet for velkomsthilsenen, men toppen av siden skal være lik (frames/rammer er ikke brukt). Du skal altså hele tiden være innenfor index.php, men innholdet som følger etter den horisontale streken skal varieres. Dette gjelder også for menyvalgene Laget og Trenerens hjørne hvor informasjonen hentes fra henholdsvis laget.html og trener.html. Filene ligger lagret i en katalog som heter filer under rota. Hvis brukeren velger Kjøp billetter skal brukeren omdirigeres bort fra index.php og sendes til en helt ny side, nemlig billetter.php. Den ligger på rotnivå. Hint: header("location:side.php") omdirigerer til en ny side. Side 2 av 11
Svar a: <html><head><title>aitel Gunners</title></head><body> <a href="index.php"><img src="bilder/logo.jpg"></a> <form method="post" action=""> <select name="meny"> <option>nyheter</option> <option>laget</option> <option>trenerens hjørne</option> <option>kjøp billetter</option> </select> <input type="submit" name="knapp" value="velg"> </form> <hr> <?php if (!isset($_post['knapp'])) { //første gang siden lastes echo "Velkommen til AITeL-Gunners sine nettsider!<br> Her finner du alt om det som rører seg i klubben vår. <br> Velg i menyen over og klikk på knappen for å navigere gjennom sidene"; else { switch ($_POST['meny']){ case "Nyheter" : include "filer/nyheter.html"; break; case "Laget" : include "filer/laget.html"; break; case "Trenerens hjørne" : include "filer/trener.html"; break; case "Kjøp billetter" : header("location:billetter.php"); break;?> </body></html> MERK: Her antas at output buffering er slått på. Det vil si at header() kan kjøres uten problemer. Normalt skal header() kjøres før output sendes til nettleseren. I koden over er dette brutt for å forenkle koden noe. Noen muligheter for å gjøre det annerledes: Bytt ut switch med if-elseif... og teksten med <HTML><HEAD><FORM> etc samt første echo-setning, legges i en variabel. Flytte logikken øverst i scriptet, og lese inn riktig filinnhold i en variabel. Deretter skrive denne ut der det passer. Side 3 av 11
b) Informasjon om kamper ligger i en database. Du skal nå programmere koden bak billetter.php. Du kan selv velge hvilket databasesystem du vil bruke. Databasen heter atlgunners og inneholder blant annet følgende tabell: Figur 1: Tabellen kamper Figur 4 i vedlegg A viser et skjema som brukeren skal fylle ut. Lag dette skjemaet. For å spare tid trenger du ikke å formattere som en tabell, og du kan også hardkode innholdet i nedtrekkslisten for tribunevalg: Felt A, Felt B, Felt C og Ståtribune. Listen for valg av kamp skal derimot være basert på innholdet fra databasen. Det skal være mulig å velge bestille mellom 1 og 20 billetter. Merk at det kun er hjemme-kamper som ikke allerede er spilt som skal kunne velges. Tips: Start med de enkleste listene først og bruk kampid som value-attributt for elementene i kamp-listen. Legg merke til at datoformatet i listen er annerledes enn i tabellen. Se også Vedlegg B. Side 4 av 11
Svar b: Viser hele siden i sammenheng her, men utfordringen ligger i å fylle listeboksene med riktig innhold. <html><head><title>aitel Gunners - billettbestilling</title></head> <body> <a href="index.php"><img src="bilder/logo.jpg"></a> <h1>billettbestilling</h1> <form method="post" action=""> <table> <tr> <td>kamp: </td> <td><select name="kamp"> <?php lagkamper();?> </select> </td> </tr> <tr> <td>tribune: </td> <td><select name="tribune"> <option>felt A</option> <option>felt B</option> <option>felt C</option> <option>ståtribune</option> </select> </td> </tr> <tr> <td>antall billetter: </td> <td><select name="antall"> <?php for ($i=0;$i<=20;$i++) echo "<option>$i</option>";?> </select> </td> </tr> <tr> <td>navn: </td> <td><input type="text" name="navn"></td> </tr> <tr><td> </td><td></td></tr> </table> <input type="submit" name="knapp" value="send bestilling"> </form> function lagkamper(){ $conn = mysql_connect("dbname=atlgunners user=b password=p"); $resultat = mysql_query($conn, "SELECT * FROM kamper WHERE bane='hjemme' AND dato >= now()"); while ($rad = mysql_fetch_array($resultat)){ $temp = explode("-", $rad['dato']); $dato = $temp[2]. ".". $temp[1]. ".". $temp[0]; $tid = $rad['tid']; $spiller = "ATG-". $rad['motstander']; $kampnr = $rad['kampnr']; echo "<option value='$kampnr'>"; echo "$dato kl $tid, $spiller</option>"; //while Side 5 av 11
c) I felt A og på ståtribunen er det plass til 1000 personer hver, og i felt B og C er det plass til 2000 personer hver. Plasser på ståtribunen koster 100 kroner, felt A koster 150 kroner, felt B koster 200 kroner og felt C har tak og koster derfor 300 kroner. Lag én matrise (array) som representerer all denne informasjonen på en fornuftig måte. Bruk gjerne tekstbaserte nøkkelverdier. Svar c: $prismatrise = array( "Ståtribune" => array("plasser" => 1000, "pris" => 100), "Felt A" => array("plasser" => 1000, "pris" => 150), "Felt B" => array("plasser" => 2000, "pris" => 200), "Felt C" => array("plasser" => 2000, "pris" => 300) ); Tabellen billettsalg har informasjon om hvem som har bestilt billetter til de ulike kampene. Denne tabellen blir etter hvert nokså stor. Her er et utdrag av noen få oppføringer. Figur 2: Tabellen billettsalg har informasjon om bestillinger til de ulike fotballkampene. Referansenummeret økes fortløpende, og når 9999 er nådd starter det på nytt med B-0000 og så videre. d) Lag en funksjon som sjekker at det er nok ledige billetter i tribunefeltet som ble valgt for den aktuelle kampdagen til å kunne foreta en reservasjon. La funksjonen returnere true hvis det er mulig å foreta reservasjon, false ellers. Hint: Du vet fra matrisen i oppgave c) hvor mange plasser et tribunefelt har. Husk at feltet kampid identifiserer en kamp unikt (jamfør tabellen kamper i Figur 1). Studér innholdet i tabellen billettsalg, og se Vedlegg B. Dersom du ikke gjør denne oppgaven kan du likevel løse oppgave e). Side 6 av 11
Svar d: //Kalles slik: sjekkledige($_post['antall']); function sjekkledige($antall){ global $prismatrise; $sql = "SELECT antall_billetter FROM billettsalg WHERE kampid=". $_POST['kamp']. " AND tribune = '". $_POST['tribune']. "'"; $resultat = mysql_query($sql); $sum = 0; while ($rad = mysql_fetch_array($resultat)) $sum += $rad['antall_billetter']; //ikke nødvendig dersom spørringen bruker select sum() $maks_antall = $prismatrise[$_post['tribune']]['plasser']; if ( ($maks_antall - $sum - $antall) > 0 ) return true; else return false; e) Figur 5 i vedlegg A viser to situasjoner etter at knappen Send bestilling er trykket. Lag scriptet kvittering.php der du bruker funksjonen fra oppgave d) til å sjekke om det er mulig å foreta en reservasjon. Hvis det går, skal databasen oppdateres slik at plassene reserveres. Sjekk først at navnet som skrives inn kun består av tekst. Dersom noe går galt skal brukeren få beskjed om dette og få mulighet til å endre opplysningene. Dersom alt går bra, skal brukeren få se antall valgte billetter og tribunefelt, totalprisen og et unikt reservasjonsnummer (består av én bokstav og fire sifre som forklarg i Figur 2). Dersom du har det travelt, så forklar med tekst hvordan du vil generere referansenummeret. Side 7 av 11
Svar e: define("tilbake", "<a href=\"javascript:history.go(-1)\"> Tilbake</a>"); if (!sjekkledige($_post['antall']) ){ die ("Det var ikke nok ledige billetter. Velg et annet felt<p>". TILBAKE); else{ if (! ereg("^[a-za-zæøåæøå ]+$", $_POST['navn']) ){ die ("Navnet er ikke riktig skrevet inn<p>". TILBAKE); $res = "A-3884"; //må hente ut siste fra databasen og øke med 1 $sql = "INSERT INTO billettsalg (kampid, tribune, antall_billetter, navn, referansenr) VALUES ($_POST[kamp], '$_POST[tribune]', $_POST[antall], '$_POST[navn]', '$res')"; //echo $sql; if (!$resultat = mysql_query($sql) ){ die("noe gikk galt, prøv igjen senere"); //OPPSUMMERINGEN echo "<p>reservasjonsnummer: <strong>$res</strong><br>"; echo "Antall billetter: $_POST[antall], $_POST[tribune]<br>"; $pris = $prismatrise[$_post['tribune']]['pris']; echo "Totalpris: ". $pris * $_POST['antall']; f) Klubben ønsker å tilby så brukervennlige sider som mulig. Det er litt tungvindt å måtte fylle ut navn og ønsket tribunefelt hver gang en fotballentusiast skal bestille billetter til en kamp. Klubben ønsker at dette skal være forhåndsvalgt hvis mulig. Hva må gjøres for å realisere dette? Beskriv hvordan dette kan gjøres og vis med kode hva som må endres i bestillingsskjemaet. Svar f: Bruke cookies til å lagre navn og sist valgte tribunefelt. Dermed kan dette forhåndsutfylles. //forhåndsinnfylle tribunefelt $valg = array( Ståtribune, Felt A, Felt B, Felt C ); foreach ($valg as $felt){ echo <option if ($_COOKIE[ tribune ] == $felt) echo SELECTED echo >$felt</option> ; //forhåndsinnfylle navn echo <input type= text name= navn ; if (isset($_cookie[ navn ])) echo value=. $_COOKIE[ navn ]. > Side 8 av 11
Vedlegg A Skjermbilder fra nettstedet. Som du ser reflekterer ikke nedtrekkslisten hva som er valgt. Figur 3: Visning av index.php i 3 ulike tilstander. Første gang siden lastes, og når Laget og Nyheter er valgt. Merk at adressen er den samme i alle tilfeller. Frames (rammer) er ikke brukt. Side 9 av 11
Figur 4: billetter.php har et skjema som brukeren kan fylle ut for å bestille billetter. Figur 5: Oppsummeringssiden kvittering.php viser to ulike situasjoner. Dersom navnet ikke er riktig utfylt vil også en feilmelding om det vises. Side 10 av 11
Vedlegg B Her finner du nyttige SQL-spørringer som kan brukes. Hent ut data om hjemmekamper: SELECT * FROM kamper WHERE bane = 'hjemme' Få et resultatsett med reserverte billetter i et visst tribunefelt i en bestemt kamp: SELECT antall_billetter FROM billettsalg WHERE kampid=4 AND tribune = 'Felt C' Lagre en bestilling i databasen INSERT INTO billettsalg (kampid, tribune, antall_billetter, navn, referansenr) VALUES (4, 'Felt C', 18, 'Ola Nordmann', 'A-7623') Side 11 av 11