1. Indholdsfortegnelse

Størrelse: px
Starte visningen fra side:

Download "1. Indholdsfortegnelse"

Transkript

1 1. Indholdsfortegnelse 1. Indholdsfortegnelse 1. Indholdsfortegnelse Indledning Analyse Databasedesign Hvilke data Standard spørgsmål Primærnøgler Transaktioner Sikkerhed ved sletninger Bevis for 3nf Webinterface Udvidelser af spørgeskemasystemet Programbeskrivelse Brugervejledning Opstart og login Brug af spørgeskemasystemet Afprøvning Konklusion Litteraturhenvisninger Afprøvning Programudskrift tables.sql adminininterface.php answerquestions.php create_course.php createquestions.php db_connect.php default.php functions.php login.php

2 1. Indholdsfortegnelse logout.php showhide.css showhide.js StyleSheet.css users.php viewanswers.php

3 2. Indledning 2. Indledning Dette er besvarelsen af rapportopgaven på Datalogi V-databaser forår Opgaven går ud på at analysere, designe og konstruere en A) spørgeskemadatabase eller B) et valgfrit emne af samme sværhedsgrad. Vi har valgt at implementere opgave A, som er beskrevet i [1] afsnit 5. Til etablering af webgrænsefladen benyttes PHP og det underlæggende databasesystem er PostgreSQL. Vi har valgt ikke at lægge nævneværdig vægt på layout eller brugervenlighed, da dette falder uden for opgavens formål. Opgavens resultat er, at det er lykkedes os at løse opgaven tilfredsstillende. Afprøvningen har ikke fundet fejl og viser derfor at systemet virker. 3

4 3. Analyse 3. Analyse Hvad spørgeskemasystemet skal kunne er beskrevet i [1] afsnit 5. Men kort fortalt så drejer det sig om at konstruere et spørgeskemasystem til brug på f. eks. skoler eller andre uddannelsesinstitutioner. Der er dog en række uklarheder og problemer, som vi i det følgende vil afklare for til sidst at komme frem til et konsistent databasedesign. I opgaven er der specificeret tre typer brugere: elever, lærere og administratorer. Elever skal kun kunne svare på de kurser, som de har. Vi er derfor nødt til at have informationer om det. Det betyder, at vi skal have en liste over de fag, som en elev har. Det er ikke defineret om en lærer skal kunne oprette spørgsmål til et fag, som læreren ikke står som ansvarlig for. Da det ikke nødvendigvis er læreren selv, der har oprettet et givent kursus og fordi, der kan være flere lærere tilknyttet et kursus, har vi valgt at alle lærere kan oprette spørgsmål til alle kurser. Herved undgår vi også at have en liste over fag som en lærer må oprette spørgsmål til. Det skal være muligt for en lærer at redigere eller slette spørgsmål til en undersøgelse. Umiddelbart virker det ikke hensigtsmæssigt at dette er muligt, hvis først et spørgsmål er besvaret. Men da dette er et krav, vil vi blot gøre opmærksom på uhensigtsmæssigheden heri, da man så kan manipulere med resultatet af en undersøgelse. Man kan således slette, tilføje eller omformulere spørgsmål efter nogle eller alle brugere har besvaret et spørgeskema. Der er defineret tre vigtige spørgsmålstyper, og det skal på sigt være muligt at udvide med nye spørgsmålstyper. Dette opfatter vi som, at det skal være muligt at tilføje nye typer til databasen uden, at der skal ændres ved designet i databasen. Dog vil det sandsynligvis indebære ændringer i implementationen, dvs. i PHP-koden, når den nye type skal præsenteres på spørgeskemasystemets hjemmeside. Når der bliver oprettet et spørgeskema med de tilhørende spørgsmål bør disse ikke blive gjort tilgængelige for brugeren før spørgeskemaet er færdigoprettet. Hvis de bliver gjort tilgængelige tidligere kan brugere komme til at udfylde spørgsmål, der ikke er færdige, og derved kan deres besvarelser ikke bruges senere. Her kan det diskuteres om der overhovedet skal gives adgang til at ændre spørgeskemaer. 4

5 3. Analyse Ligeledes kan det diskuteres om spørgeskemaerne skal offentliggøres med det samme. Der kunne gives mulighed for at vælge hvornår et spørgeskema skal være aktivt fra. Dette kunne enten gøres ved at have et felt, der angiver om spørgeskemaet er aktivt, eller ved at have et dato felt der kunne angive hvilken periode spørgeskemaet skal være aktivt i. Vi har dog fundet dette for vidtgående for denne opgave og derfor er dette ikke taget med i vores design. Derudover kan der opstår problemer, hvis der bliver ændret i spørgsmålene mens en bruger er ved at besvare spørgeskemaet. Dette skyldes, at systemet ikke ved hvilken version af spørgeskemaet brugeren har udfyldt, og derfor vil forsøge at indsætte forældet data i spørgeskemaet. Dette kan undgås ved at give hvert spørgeskema et løbenummer og ved hver ændring i strukturen bliver løbenummeret talt op derved kan systemet checke for om løbenummeret på skemaet brugeren har udfyldt stemmer overens med løbenummeret på spørgeskemaet, der findes i databasen. Dette er dog for meget i forhold til opgavens omfang. Systemet kan opdeles i to dele. Den ene del er selve databasen, som beskriver den grundlæggende datamodel og gemmer de af brugeren indtastede data. Den anden del er selve præsentationslaget, samt den logik der behøves for at fremvise de data der findes i databasen. Denne del ligger på en webserver Databasedesign Hvilke data Det har været et krav til opgaven at undgå redundante data. I vores endelige design har vi 8 tabeller. Der skal gemmes oplysninger om hvilke brugere, der har adgang til systemet og hvilke funktioner, brugeren har adgang til, herunder oprettelse af brugere eller svar på spørgsmål mm. Dette kan enten gøres ved at hver brugertype får sin egen tabel, eller det kan gøres ved at have en tabel for alle brugere og derudover også gemme brugertypen med hver 5

6 3. Analyse enkelt bruger. Grundlæggende er der kun behov for at gemme: navn, login og password for hver enkelt bruger, og dette er fælles for alle brugertyperne. Vi har valgt at have én tabel med brugeroplysninger, samt en brugertypetabel som angiver hvilken type bruger, der er tale om. Denne skal hovedsageligt bruges til at styre rettighederne til de forskellige funktioner i systemet. Valget med kun at have én brugertabel skyldes, at de informationer, der er behov i forbindelse med brugerne, er ens for alle typer. Naturligvis ville denne metode ikke være optimal, hvis der var forskel på de informationer systemet skulle gemme om hver enkelt bruger dette er dog ikke tilfældet. Endvidere giver dette design mulighed for hurtigt at udvide med endnu en brugertype ved at tilføje en række til brugertype tabellen. Der skal dog stadig laves ændringer i webinterfacet (PHP koden), men i langt mindre omfang end tilfældet, hvor hver brugertype har sin egen tabel. Systemet skal også give mulighed for at oprette spørgsmål, ligeledes skal brugerne have mulighed for at svare på disse spørgsmål dvs. deres besvarelser skal gemmes. Det er et krav i opgaveteksten [1], at der er mindst tre type spørgsmål a) uddybende spørgsmål, hvor der svares med en tekststreng, b) valgmuligheder, hvor brugeren bliver præsenteret for et antal muligheder, som der kan vælges i mellem eller c) som består både af a) og b). Overvejelserne i forbindelse med dette har været om der skulle laves tre spørgsmålstabeller. Her er det klart, at ikke alle informationerne er ens for alle spørgsmålstyperne, dog er det sådan at typen c) er en blanding af to de to andre typer. Fælles for alle spørgsmålstyperne er en tekst, der beskriver spørgsmålet. Derudover kan spørgsmålet have en valgmulighed, der beskriver valgmulighederne. Ligeledes vil der ved hvert svar være knyttet oplysninger, der passer til spørgsmålstypen. Hvis der vælges separate tabeller til hver spørgsmålstype bør der også vælges separate tabeller til hver svartype. Dette vil sikre en ensartethed af designet. Med separate tabellere til hver type vil der ikke findes overflødige felter i hverken svar- eller spørgsmålstabellerne. Dette vil dog også gøre alle forespørgsler til databasen ifb. Spørgsmål eller svar væsentligt mere komplicerede, fordi tabeller og felter er afhængig af type af spørgsmål. Derfor har vi valgt at holde os til en svar tabel og en spørgsmålstabel, netop for at bevare så meget ensartethed i systemet som muligt. En lang række operationer ville 6

7 3. Analyse blive mere komplicerede og langsommere hvis der var en svartabel for hver spørgsmålstype. Endvidere ville en tilføjelse (eller fjernelse) af en spørgsmålstype betyde ret betydelige ændringer i PHP-koden samt de SQL udtryk, der bliver sendt til databasen. Ved at have en spørgsmålstype tabel kan meget af dette holdes så ensartet, at nye typer kan tilføjes uden ændringer i koden. Vi har begrænset opgaven, således at der kun kan være et spørgeskema pr. fag. Det er derfor ikke muligt at lave flere evalueringer i et fag medmindre at man opretter et nyt kursus og tilknytter eleverne til kurset Standardspørgsmål Der skal implementeres standardspørgsmål, som skal gælde for alle spørgeskemaer. Dette kan løses på flere måder. løsninger vi har overvejet er 1) oprette et ekstra felt i spørgsmålstabellen, der angiver om det er et standardspørgsmål, 2) oprette et dummy kursus, hvori standardspørgsmål tilknyttes eller 3) oprette flere spørgsmålstyper. Sidstnævnte kan vi dog udelukke med det samme, da det giver et uhensigtsmæssigt design, hvilket man kan se ved at forestille sig følgende. Vi har allerede tre spørgsmålstyper A, B, og C (dvs. uddybende spørgsmål, valgmuligheder og valgmuligheder med mulighed for uddybning), opretter vi således en ny type D, som er standardspørgsmål, så skal der for hver A, B og C konstrueres en tilsvarende type for D som indeholder mulighed D+A, D+B og D+C, hvilket er uhensigtsmæssigt. Ved løsning 1) tilknyttes standardspørgsmålene til forskellige kurser, hvilket giver problemer, når et kursus slettes og tilhørende spørgsmål skal slettes. Nu skal der tages højde for om det er standard spørgsmål, hvilket komplicerer sletning væsentligt. Vi vælger derfor løsning 2) hvor vi opretter et specielt kursus, som indeholder alle standardspørgsmålene. Dette letter også arbejdet, når vi skal lave et interface til at redigere og oprette standardspørgsmål. Problemet er dog at der i forskellige situationer skal tages særskilt højde for standardspørgsmålskurset for det er jo som sådan det er lagret i databasen. Dette kursus skal ikke vises for brugeren af spørgeskemasystemet i en række tilfælde. F. eks. når der skal genereres en liste over kurser, som man kan tilmelde en studerende til, så skal standardspørgsmålskurset ikke vises. Når der svares på et standardspørgsmål skal svaret knyttes til det kursus, som der bliver svaret på. Dette løser vi ved at oprette et felt i svartabellen, hvori kurset 7

8 3. Analyse gemmes. Det vi opnår er at man kan svare på samme spørgsmål flere gange uafhængigt af hinanden, hvilket bruges ved standardspørgsmålene Primærnøgler Ved design af de enkelte tabeller er det nødvendigt at finde en primærnøgle. Denne nøgle skal bruges til at identificere de enkelte rækker fra hinanden. I det system vi ønsker at opbygge har primærnøglen endvidere en funktionalitet i forbindelse med webserveren. Fordi websiderne stort set er stateless er det nødvendigt at sende informationer med mellem de enkelte sider der unikt beskriver hvilke data, vi ønsker at arbejde på. Dette kan kun gøres ved at sende en identifikation, i form af en nøgle, med rundt til de enkelte sider, som fortæller hvilke data operationen ønskes udført på. Til dette er det oplagt at benytte primærnøglen, da vi ved at denne er unik, samt at der er hurtigt for database systemet at lave opslag på baggrund af en primærnøgle. For langt de fleste tabeller, vi har beskrevet, kan der nemt findes en primær nøgle som består af et eller flere felter. Fx. kan der ved brugertabellen vælges login og password som primærnøgle, eller ved tabellen med kurser kan der bruges kursusnavnet. I begge tilfælde vil nøglerne være unikke som krævet. Desværre er det problematisk at skulle sende så mange data rundt mellem de enkelte sider, især i nogen tilfælde ønsker bruger måske ikke data gemt i browserens history. Her vil det f. eks. være uhensigtsmæssigt at sende brugernavn og password videre. Udover disse problemer er der enkelte tabeller, hvor der ikke umiddelbart kan findes en primærnøgle, og hvor der derfor må tilføjes en id, fx. i form af et løbenummer. Derfor har vi valgt at holde løsningen ensartet ved at tilføje et idnummer til alle tabeller og benytte dette id nummer som primærnøgle. Vi mener denne løsning er langt pænere og mere effektiv. Derudover har vi fordelen af at et idnummer er hurtigt at sammenligne på og det fylder lidt, også når det skal sendes videre mellem de enkelte sider Transaktioner Ved et system som dette, hvor der kan forekomme mange samtidige brugere, som opdaterer data, er det vigtigt at sikre en integritet af de data, der arbejdes på. Langt størstedelen af dette bliver automatisk varetaget af database management systemet. 8

9 3. Analyse Dog kan der nemt tænkes situationer, hvor data bliver tilføjet i flere omgange. Når en bruger har besvaret et spørgeskema, skal brugerens svar indsættes i databasen. Dette vil sige at der, med vores design, skal indsættes et antal rækker i tabellen der indeholder brugerens svar. Med SQL er der kun mulighed for at indsætte én række adgangen (med undtagelse af INSERT INTO hvor der tages data fra en anden tabel). Her kunne man sagtens forestille sig, at serveren oplever et nedbrud inden alle disse inserts er tilendebragt. Det første som der kan gøres for at undgå dette ville være at sende alle inserts som én samlet SQL-streng. Dette er dog kun med til at minimere sandsynligheden for et nedbrud inden alle statements i strengen er udført. Man kunne forstille sig at der bliver sat et flag på hver enkelt række i svartabellen som efter alle svar i forbindelse med et givent spørgeskema er blivet indsat bliver sat. Dette kunne gøres med en enkelt update, som er atomisk. Efter et nedbrud kunne administratoren simpelthen slette alle række som ikke har dette flag sat da disse må være ikke fuldstændig i forhold til hele spørgeskemaet. En mere sikker måde at gøre dette på er at udnytte PostgreSQL mulighed for transaktioner hvis en transaktion af den ene eller anden grund ikke bliver gennemført bliver ingen dele af transaktionen gennemført. Derudover sikrer transaktioner os mod at data fra spørgeskemaer, hvor alle svar ikke er blevet indsat, bliver medtaget, hvis en anden bruger beder om at se besvarelserne Sikkerhed ved sletninger For at sikre at databasens integritet altid er opretholdt, er det nødvendigt at sikre, at der ikke bliver indsat data i felter, som er ugyldige, og at der ved sletninger ikke bliver slettet dele af data. Fejl som dette kan naturligvis undgås ved at validere input fra brugeren, samt ved at skrive gennemtænkt SQL kode. Vi har dog fundet dette urealistisk, derfor er der tilføjet en række constrants til databasen. For at opretholde dette har vi tilføjet constraints efter disse grundlæggende regler: Alle fremmedenøgler må ikke være NULL, med mindre der er en god grund til dette Alle navne skal være unikke dette skyldes især at brugerne skal kunne skelne mellem de forskellige navne på fx kurser. Har to kurser samme navn vil kun deres id adskille dem og dette kan brugerne ikke umiddelbart se. 9

10 3. Analyse Når der slettes skal dette være som cascade dette følges stort set af regel 1, hvis fremmednøglerne ikke må være NULL skal rækken slettes ellers vil værdien ikke være gyldig. De undtagelser vi har fra ovenstående regler er: Person må godt have ens navne, loginnavne og passwords. Dog skal loginnavn sammenholdt med password være unikt. Dette er naturligvis et krav, da systemet ellers ikke vil kunne skelne to logins fra hinanden. Dog kan navnet på en bruger godt være ens med en anden brugers navn dette skyldes at der i den virkelige verden tit opstår navnesammenfald mellem personer. At password ikke skal være unikt skyldes, at de sagtens kan tænkes at to brugere ønsker det samme password og systemet skal naturligvis ikke afholde folk fra dette. Spørgsmålsnavne behøver ikke være unikke, hvilket skyldes, at vi hurtigt kan finde formuleringer som ofte vil gå igen. Derudover behøver brugeren ikke skelne de forskellige spørgsmål fra hinanden, men bare forholde sig til det enkelte spørgsmål. I svartabellen er der ikke noget krav om, at et svar skal indeholde en optionid altså at svaret skal indeholde værdien fra en option. Som nævnt ovenfor vil deletes altid være cascade ved fremmenøgler, hvilket vi gennemgående har holdt gennem hele databasedesignet. Nedenstående diagram viser det endelige design, beskrevet i UML syntaks. De fleste af tabellerne er der ikke noget at sige til ud over det der allerede er beskrevet i analysen. Dog fortjener relationerne Person, Course og PersonCourse et par ord med på vejen. Fordi en person kan deltage i flere kurser og et kursus kan have flere tilmeldte personer, har vi løst dette ved at oprette en ekstra tabel PersonCourse som går at vi kan have denne mange til mange relation. 10

11 3. Analyse 11

12 3. Analyse Bevis for 3. normalform Vi går ud fra [2] side 617 og det der er gennemgået i øvelserne. PersonType(persontypeId, name) FD kan udledes fra primærnøglen persontypeid at A B og name skal være unik, derfor fås B A. Ud fra dette kan vi finde følgende kandidatnøgler: A + = AB og B + = AB. Det ses nu at A og B er kandidatnøgler samt at der ikke er flere mulige kombinationer. QuestionType(questionTypeId, typename) FD kan udledes fra primærnøglen questiontypeid at A B og typename skal være unik, derfor fås B A. Ud fra dette kan vi finde følgende kandidatnøgler: A + = AB og B + = AB. Det ses nu at A og B er kandidatnøgler samt at der ikke er flere mulige kombinationer. Course(courseId, name, personid) FD kan udledes fra primærnøglen courseid at A B og A C og name skal være unik, derfor fås B A og B C. Ud fra dette kan vi finde følgende kandidatnøgler: A + = ABC, B + = ABC og C + = C. Det ses nu at A og B er kandidatnøgler. C kan ikke være en kandidatnøgle, da C + = C, A og B er allerede kandidatnøgler og kan derfor ikke være en del af kandidatnøgle med C. Person(personId, name, login, password, persontypeid) Ud fra personid, som er primærnøgle, kan vi udlede A B, A C, A D og A E. Derudover så ved vi at login + password er unikt, dvs. CD A, CD B og CD E. Så kan vi finde kandidatnøgler: A + = ABCDE, CD + = ABCDE. Vi har at B + = B, C + = C, D + = D og E + = E. A er kandidatnøgle og det er CD også. C og D kan ikke være kandidatnøgler, da de allerede er en del af en kandidatnøgle. BE + = BE og det er ikke en kandidatnøgle. Vi har nu været alle kombinationer igennem og har fundet at A og CD er kandidatnøgler. 12

13 3. Analyse PersonCourse(personCourseId, personid, courseid) FD kan udledes fra primærnøglen personcourseid: A B og A C. personid + courseid er unikt, dvs. at BC A. Kandidatnøgler: A + = ABC og BC + = ABC. Alle nøgler er brugt, hvorfor der ikke kan være flere kandidatnøgler. Question(questionId, courseid, questiontypeid, placement, name) FD kan udledes fra primærnøglen questionid: A B, A C, A D og A E. Vi kan finde følgende kandidatnøgler: A + = ABCDE. Mulige kandidatnøgler: B + = B, C + = C, D + = D og E + = E. Vi kan se at A kun optræder på højresiden af kandidatnøglen A. Derfor kan der ikke findes andre kombinationer, som er kandidatnøgler. A er den eneste kandidatnøgle. Option(optionId, questionid, placement, name) Igen kan FD udledes fra primærnøglen optioned: A B, A C og A D. Vi kan finde følgende kandidatnøgler: A + = ABCD. Mulige kandidatnøgler: B + = B, C + = C, og D + = D. Ligesom relationen Option kan vi se at A kun optræder på højresiden på kandidatnøglen A. Derfor kan der ikke findes andre kombinationer, som er kandidatnøgler. A er den eneste kandidatnøgle. Answer(answerId, questionid, optionid, personid, courseid, answertext) FD udledes fra primærnøglen answerid: A B, A C, A D, A E og A F. derudover fås: BDE A og BDE C. Årsagen til at courseid er taget med er på grund af standardspørgsmålene. Kandidatnøgler: A + = ABCDEF, BDE + = ABCDEF. Mulige nøgler: C og F. Vi har C + = C og F + = F. Ingen kombinationer af disse kan være en kandidatnøgle. Vi har derfor fundet kandidatnøglerne til at være A og BDE. Af ovenstående gennemgang af de enkelte relationer ses at de alle er på 3. normalform. Årsagen hertil er at de alle opfylder de krav til 3. normalform som er beskrevet i [2] side Webinterface I opgaveteksten [1] afsnit 5 stilles en række krav til funktionalitet, som vi skal implementere. Vi har valgt at lave følgende sider: 13

14 3. Analyse Login og logud side Brugeradministration o Oprettelse af brugere, brugerrettigheder o Tilmelding af studerende til kurser o Kun adgang for administratorer Kursusadministration o Oprettelse af kurser o Adgang for lærer og administratorer Opret spørgsmål o Administration af spørgeskemaer. o Adgang for lærer og administratorer Svar på spørgsmål o Adgang for personer, der er tilknyttet et kursus, dvs. man kan kun svare på de kurser som man er tilmeldt. Se svar på spørgsmål for alle kurser. Administrator interface o Mulighed for at skrive en vilkårlig SQL kommando til databasen o Kun adgang for Administratorer. Brugeradministrationen er ikke et krav. Vi synes dog, at det er en forholdsvis lille og logisk tilføjelse, der vil lette arbejdet for administratoren af spørgeskemasystemet og i øvrigt bidrager til, at der ikke kræves specielle forudsætninger for at kunne administrere spørgeskemasystemet. Systemet skal bygges op således, at der ikke kan ske fejl eller værre endnu, at man ikke kan ødelægge systemet, når man navigerer rundt på ovenstående sider. Dog med undtagelse af administratorinterfacet. Her er det næsten umuligt at gardere sig og vi må i stedet sætte vores lid til at administratoren ved, hvad vedkommende gør! Databasedesignet gør, at databaseadministratoren ikke kan indtaste ugyldige data, f. eks. ugyldige primærnøgler og referencer, der ikke passer med primærnøgler. 14

15 4. Udvidelser af spørgeskemasystemet 4. Udvidelser af spørgeskemasystemet Vi har igennem i rapporten omtalt en række forbedringerne som med fordel senere kunne implementeres. Vi har her valgt at lave en kort opsummering af disse. Låsning af spørgeskema, således at spørgsmål ikke kan redigeres eller tilføjes, når der en der har svaret på spørgeskema. Sikring mod at flere lærer redigerer i de samme spørgsmål på den samme tid Fejlhåndtering: Når der forsøgets at skrive ugyldige ting til databasen, f. eks. i forbindelse med ugyldigt brugerinput. Dette kunne være forsøg på at oprette kurser med samme navn eller lign. Forbedring af layout herunder printvenlige sider uden farver. Backup via interface således at administratoren kan tage backup af databasen via. webinterfacet. Mulighed for at lave flere spørgeskemaer pr. kursus kræver blot en ekstra tabel, der holder styr på det. Alle disse ideer ville dog gøre systemet for stort i forhold til opgavens omfang. 15

16 5. Programbeskrivelse 5. Programbeskrivelse I dette tilfælde består vores program af websider i HTML, der bliver genereret ved hjælp af PHP. Når man benytter PHP og HTML kan man vælge at gribe det an på to forskellige måder. Enten blander man PHP og HTML sammen eller også genereres alt HTML ud fra PHP. Vi har valgt sidstnævnte, da koden ellers let bliver meget uoverskuelig. Endvidere bliver koden afviklet hurtigere, når man bruger denne metode. Vi har samlet de vigtigste funktioner i en fil (functions.php). Derudover har vi lavet særskilte filer, der holder styr på login og sørger for at koble op til databasen (db_connect.php). I functions.php findes en lang række generelle funktioner som benyttes gennem hele løsningen. Vi har til HTML koden benyttet os af cascading stylesheets i mindre udstrækningen dette er kun gjort for at gøre siderne mere visuelt overskuelige, og tidsforbruget ved at benytte stylesheets har været meget lille da der var tale om genbrug fra et tidligere udviklet system. En teknisk ting: Udtage idnummeret på den række som man er ved at sætte ind i tabellen. Dette havde vi ikke fundet en metode til, da vi først konstruerede koden. Vi har så senere fundet ud af at metoden curval() kan klare jobbet for os. Vi har ikke implementeret dette. Konsekvenserne af dette er at vi enkelte steder må foretage to til tre kald til databasen, hvor det i stedet kunne klares med et kald, og at vi har krævet at enkelte felter skal være unikke. Selvom vi har bestræbt os på at bruge transaktioner ved alle opdatering af databasen mangler dette på enkelte sider. Dette skyldes simpelthen tidspres. Der er intet til hinder for at dette også bliver implementeret de sidste steder, hvor dette mangler. 16

17 6. Brugervejledning 6. Brugervejledning Spørgeskemasystemet findes på konto - di Opstart og login 1. Opstart af PostgreSQL databasesystem Login på linuxhost Grerr og skriv postmaster D /var/tmp/db-di Hvis databasen ikke findes, skal denne først oprettes. Dette gøres på følgende måde i en nterm: o Skift til katalog ~di020275/db/ o psql p h grerr.diku.dk U di template1 o indtast pasword: gravko o \i tables.sql; 2. Start af webserver Login på linuxhost Fjalar og skriv httpd d $HOME/www-root 3. Login på systemet Systemet kommer nu frem og spørger efter brugernavn og password. Benyt brugernavn admin og password Denne bruger har adgang til alle funktioner i systemet Brug af spørgeskemasystemet Menuen til venstre afhænger af hvilke rettigheder brugeren har. Menuen er inddelt i tre grupper: 1. Administratorer, som har adgang til alt 2. Lærerer som har adgang til at oprette spørgsmål, kurser og brugere plus alt hvad eleverne har adgang til. 3. Elever kan besvare spørgeskemaer på fag som de følger og se besvarelser. Benyt følgende fremgangsmåde, når der skal oprettes kurser, brugere og spørgeskemaer. Det nemmeste er først at oprette kurserne og efterfølgende oprette brugerne, da man så i samme arbejdsgang kan tilknytte brugerne til de relevante kurser. 17

18 7. Afprøvning 7. Afprøvning Det er svært at afprøve et interaktivt system, idet man kan forestille sig mange forskellige cases. Vi har valgt at konstruere et lille eksempel, som skal illustrere at vores spørgeskemasystem virker. Vi starter med en tom database, dog med en administrator, som har adgang til systemet. Vi vil afprøve følgende case: Kurser: Dansk Engelsk Brugere: Administrator Stud1 - har dansk Stud2 - har engelsk og dansk Teacher1 - underviser i dansk og engelsk 1. Administratoren opretter kurser og brugerne teacher1, stud1 og stud2 i overensstemmelse med ovenstående oversigt. Til dette benyttes menupunkterne kurser og brugere. 2. Administratoren opretter en række standardspørgsmål, som skal gælde for alle spørgeskemaerne: 1. køn valgmulighed a) mand eller b) kvinde 2. fødselsår uddybende 3. Teacher1 opretter et spørgeskema til hvert af fagene (dansk og engelsk). Læreren benytter nedenstående oversigt: 1. Hvad synes du om faget (dansk/engelsk)? uddybende 2. Hvordan var din arbejdsindsats? valgmulighed a) god, b) middel eller dårlig 3. Vurder underviserens formidlingsevne uddybende og valgmulighed a) god middel, b) middel eller c) dårlig 18

19 7. Afprøvning 4. Kun for faget engelsk: Hvor sandsynligt er det at du fortsætter til næste år valgmulighed a) sandsynligt eller b) mindre sandsynligt 4. Stud1 svarer på spørgeskemaet for dansk 1. Kvinde spændende fag 4. god 5. middel uddybning: skriver for lidt på tavlen. 5. Stud2 svarer på spørgeskemaet for dansk 1. Mand Lidt trivielt men lidt for lange bøger 4. middel 5. god uddybende: alle tiders at der ikke bliver skrevet mere på tavlen 6. Stud2 svarer på spørgeskemaet for engelsk 1. Mand Alt for svært 4. Dårlig 5. Dårlig uddybning: der bliver talt for meget engelsk 6. mindre sandsynligt 7. Teacher1 ser svarene på spørgeskemaerne 1. Dansk - klikker på linket vis alle tekstsvar 2. Dansk - klikker på linket vis alle tekstsvar 8. Teacher1 finder en stavefejl i spørgeskemaet for engelsk i spørgsmålet: Hvad synes du om faget engelsk. Engelsk var skrevet med stort E. Dette bliver nu rettet. 9. Teacher1 sletter spørgsmålet: Vurder underviserens formidlingsevne for spørgeskemaet for engelsk. Det forventede resultat af ovenstående case (1-9) er at det kan lade sig gøre uden nogen problemer. 19

20 7. Afprøvning Særskilte små tests: 10. Oprettelse af to kurser med samme navn. 11. Stud1 forsøger at få adgang til side, hvor brugeren ikke må logge ind, dvs. stud1 skriver stien til create_course.php 12. Administrator interface 1. Udtag alle brugere fra databasen ordnet efter navn. 2. Indtastning af fejlbehæftet sql SELECT * FROM person ORDER name ASC (mangler BY). Det forventede resultat af case er det forventede resultat at intet af det kan lade sig gøre på nær 12.1, hvor brugerne skrives pænt ud. Resultatet af testen kan ses i afsnit Til hver case findes et eller flere skærmdumps med en beskrivende tekst. F. eks. findes der til case 1 følgende skærmdumps: 1a, 1b, 1c og 1d. Det kan ses at alt forløber som forventet. 20

21 8. Konklusion 8. Konklusion Vi har konstrueret et spørgeskemasystem, som opfylder kravene i [1] med enkelte tilføjelser. Specielt er det muligt at administrere brugere uden at skulle benytte direkte PosqreSQL statements til databasen. Herved har vi konstrueret et system som kan stå for sig selv og man behøver derfor ingen kendskab til SQL eller databaser for at kunne bruge spørgeskemasystemet. Afprøvningen finder ingen fejl, så det er sandsynligt, at vores system virker, men da testen ikke er udtømmende kan vi dog ikke fraskrive os, at der ikke kan have indsneget sig enkelte fejl. Dog kunne vi godt have ønsket os, at der var lidt større sikkerhed ved flere samtidige brugere. Alt i alt er vi godt tilfredse med det vi har nået på den afsatte tid. 21

22 9. Litteraturhenvisninger 9. Litteraturhenvisninger [1] Katajainen, Jyrki m.fl. Rapportopgave I Datalogi V-Databaser, Forår [2] Gehrke, Johannes m. fl. Database Management System, 3ed

23 10.1. Afprøvning 1a Oprettelse af kurset engelsk 23

24 1b Oversigt over oprettede kurser 24

25 1c Oprettelse af bruger stud1 25

26 1d Oversigt over brugere 26

27 2a oprettelse af standardspørgsmål køn 27

28 2b Oversigt over standardspørgsmål 28

29 3a teacher1 logget på. 29

30 3b teacher1 opretter spørgsmål: hvordan var din arbejdsindsats i faget dansk 30

31 3c Oversigt over spørgsmål i dansk 31

32 3d Oversigt over spørgsmål i engelsk 32

33 4a Oversigt over spørgeskemaer som stud1 kan svare på 33

34 4b stud 1 svarer på spørgeskema for dansk. 34

35 4c oversigt over spørgeskemaer som stud1 kan svare på efter at stud1 har svaret på spørgsmål for dansk. 35

36 5a stud2 svarer på spørgeskemaet for dansk 36

37 5b oversigt over spørgeskemaer som stud2 kan svare på efter at stud2 har svaret på spørgsmål for dansk. 6 ingen billeder 37

38 7a Oversigt over de fag der har spørgeskemaer med svar. 38

39 7b Teacher1 ser svar på dansk efter der er klikket på linket vis alle tekst svar. 39

40 7c Teacher1 ser svar på engelsk efter der er klikket på linket vis alle tekst svar. 8a resultatet kan ses på 9a 40

41 9a svar på spørgeskema efter at spørgsmål: Vurder underviserens formidlingsevne for spørgeskemaet for engelsk er slettet. 41

42 10a forsøg på at oprette et kursus med samme navn. 11a Adgang nægtet til side. 42

43 12a Indtastning af sql statement - vis alle brugere 12b resultat af 12a. 43

44 12c fejl i sql statement 44

45 10.2. Programudskrift tables.sql -- opret en database vi kan arbejde på CREATE DATABASE k1db; -- lav en bruger CREATE USER administrator; -- tildel password ALTER USER administrator WITH PASSWORD 'gravko'; -- giv administrator adgang til hele k1db GRANT ALL ON DATABASE k1db TO administrator; -- forbind til databasen \c k1db -- Database: k1db -- Schema: public CREATE SCHEMA public AUTHORIZATION "administrator"; GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC; COMMENT ON SCHEMA public IS 'Standard public namespace'; CREATE SEQUENCE public.persontypeid_seq INCREMENT 1 MINVALUE 1 MAXVALUE CACHE 1; SELECT setval('public.persontypeid_seq', 2); GRANT ALL ON public.persontypeid_seq TO "administrator"; -- Table: public.persontype CREATE TABLE public.persontype ( persontypeid int4 DEFAULT nextval('public.persontypeid_seq'::text) NOT NULL, typename varchar(20), CONSTRAINT unique_persontype UNIQUE (typename), CONSTRAINT "persontype_pkey" PRIMARY KEY (persontypeid) ); GRANT ALL ON TABLE public.persontype TO "administrator"; CREATE SEQUENCE public.questiontypeid_seq INCREMENT 1 MINVALUE 1 MAXVALUE CACHE 1; SELECT setval('public.questiontypeid_seq', 2); GRANT ALL ON public.questiontypeid_seq TO "administrator"; -- Table: public.question CREATE TABLE public.questiontype ( questiontypeid int4 DEFAULT nextval('public.questiontype_seq'::text) NOT NULL, name varchar(200), CONSTRAINT unique_questiontype UNIQUE (name), CONSTRAINT questiontype_pkey PRIMARY KEY (questiontypeid) ) WITH OIDS; GRANT ALL ON TABLE public.questiontype TO "administrator"; CREATE SEQUENCE public.personid_seq INCREMENT 1 MINVALUE 1 MAXVALUE CACHE 1; SELECT setval('public.personid_seq', 2); GRANT ALL ON public.personid_seq TO "administrator"; -- Table: public.person CREATE TABLE public.person ( personid int4 DEFAULT nextval('public.personid_seq'::text) NOT NULL, persontypeid int4 NOT NULL, name varchar(50), login varchar(20), password varchar(20), CONSTRAINT unique_personpassword UNIQUE (login, password), CONSTRAINT person_pkey PRIMARY KEY (personid), CONSTRAINT FpersonTypeId FOREIGN KEY (persontypeid) REFERENCES persontype (persontypeid) 45

46 ON DELETE NO ACTION ON UPDATE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE ); GRANT ALL ON TABLE public.person TO "administrator"; CREATE SEQUENCE public.courseid_seq INCREMENT 1 MINVALUE 1 MAXVALUE CACHE 1; SELECT setval('public.courseid_seq', 2); GRANT ALL ON public.courseid_seq TO "administrator"; -- Table: public.course CREATE TABLE public.course ( courseid int4 DEFAULT nextval('public.courseid_seq'::text) NOT NULL, personid int4 NOT NULL, name varchar(50), CONSTRAINT unique_name UNIQUE (name), CONSTRAINT course_pkey PRIMARY KEY (courseid), CONSTRAINT FpersonId FOREIGN KEY (personid) REFERENCES person (personid) ON DELETE NO ACTION ON UPDATE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE ) WITH OIDS; GRANT ALL ON TABLE public.course TO "administrator"; CREATE SEQUENCE public.personcourseid_seq INCREMENT 1 MINVALUE 1 MAXVALUE CACHE 1; SELECT setval('public.personcourseid_seq', 2); GRANT ALL ON public.personcourseid_seq TO "administrator"; -- Table: public.personcourse CREATE TABLE public.personcourse ( personcourseid int4 DEFAULT nextval('public.personcourseid_seq'::text) NOT NULL, courseid int4 NOT NULL, personid int4 NOT NULL, CONSTRAINT personcourse_pkey PRIMARY KEY (personcourseid), CONSTRAINT FcourseId FOREIGN KEY (courseid) REFERENCES course (courseid) ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FpersonId FOREIGN KEY (personid) REFERENCES person (personid) ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE ) WITH OIDS; GRANT ALL ON TABLE public.personcourse TO "administrator"; CREATE SEQUENCE public.questionid_seq INCREMENT 1 MINVALUE 1 MAXVALUE CACHE 1; SELECT setval('public.questionid_seq', 2); GRANT ALL ON public.questionid_seq TO "administrator"; -- Table: public.question CREATE TABLE public.question ( questionid int4 DEFAULT nextval('public.questionid_seq'::text) NOT NULL, courseid int4 NOT NULL, questiontypeid int4 NOT NULL, placement int4 DEFAULT 0 NOT NULL, name varchar(200), CONSTRAINT unique_courseidname UNIQUE (courseid, name), CONSTRAINT question_pkey PRIMARY KEY (questionid), CONSTRAINT FcourseId FOREIGN KEY (courseid) REFERENCES course (courseid) ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FquestionTypeId FOREIGN KEY (questiontypeid) REFERENCES questiontype (questiontypeid) ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE ) WITH OIDS; GRANT ALL ON TABLE public.question TO "administrator"; CREATE SEQUENCE public.optionid_seq INCREMENT 1 MINVALUE 1 MAXVALUE CACHE 1; 46

47 SELECT setval('public.optionid_seq', 2); GRANT ALL ON public.optionid_seq TO "administrator"; -- Table: public.question CREATE TABLE public.option ( optionid int4 DEFAULT nextval('public.optionid_seq'::text) NOT NULL, questionid int4 NOT NULL, placement int4 DEFAULT 0 NOT NULL, name varchar(200), CONSTRAINT option_pkey PRIMARY KEY (optionid), CONSTRAINT FquestionId FOREIGN KEY (questionid) REFERENCES question (questionid) ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE ) WITH OIDS; GRANT ALL ON TABLE public.option TO "administrator"; CREATE SEQUENCE public.answerid_seq INCREMENT 1 MINVALUE 1 MAXVALUE CACHE 1; SELECT setval('public.answerid_seq', 2); GRANT ALL ON public.answerid_seq TO "administrator"; -- Table: public.question CREATE TABLE public.answer ( answerid int4 DEFAULT nextval('public.answerid_seq'::text) NOT NULL, questionid int4 NOT NULL, courseid int4 NOT NULL, optionid int4, personid int4 NOT NULL, answertext varchar(2000), CONSTRAINT answer_pkey PRIMARY KEY (answerid), CONSTRAINT FquestionId FOREIGN KEY (questionid) REFERENCES question (questionid) ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FcourseId FOREIGN KEY (courseid) REFERENCES course (courseid) ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FpersonId FOREIGN KEY (personid) REFERENCES person (personid) ON DELETE NO ACTION ON UPDATE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE ) WITH OIDS; GRANT ALL ON TABLE public.answer TO "administrator"; -- DATA -- INSERT INTO persontype (persontypeid, typename) VALUES (1, 'admin'); INSERT INTO persontype (persontypeid, typename) VALUES (2, 'teacher'); INSERT INTO persontype (persontypeid, typename) VALUES (3, 'student'); INSERT INTO questiontype (questiontypeid, name) VALUES (1, 'Valgmuligheder'); INSERT INTO questiontype (questiontypeid, name) VALUES (2, 'Uddybende'); INSERT INTO questiontype (questiontypeid, name) VALUES (3, 'Uddybende med valgmuligheder'); INSERT INTO person (personid, persontypeid, login, name, password) VALUES (1, 1, 'admin', 'Administrator', '1234'); INSERT INTO course (courseid, name, personid) VALUES (1, 'standard_sporgsmaal', 1); adminininterface.php #!/usr/local/del1/datv-databaser/php/bin/php 47

48 <?php /* Giver mulighed for at sende SQL-statements direkte til databasen og se resultatet som en HTML side */ // database connect script. require 'db_connect.php'; require 'functions.php'; makepagehead('admin interface', 'admin'); if (isset($_get['exec'])) { //Fjern overflødige backslashes $query = (stripslashes($_post['sqlstr'])); $rows = pg_exec($db, $query); if($rows==false) { //En eller anden fejl er opstået, sandsynligvis //i det sql statement brugeren har indtastet echo 'Fejl i SQL'; else { //først laver vi en table, og den første //række i tabellen er feltnavnene på kolonnerne echo '<table border=1>'; echo '<tr>'; for($i = 0; $i < pg_num_fields($rows); $i++) { echo '<td>'.pg_field_name($rows, $i)."</td>"; echo '</tr>'; //hvis alle de efterfølgende rækker $numrows = pg_numrows($rows); for($i=1; $i<=$numrows; $i++) { echo '<tr>'; $row = pg_fetch_array($rows, $i-1); for($j = 0; $j < pg_num_fields($rows); $j++) { echo '<td>'.$row[pg_field_name($rows, $j)]."</td>"; echo '</tr>'; echo '</table>'; //skriv et ok - ikke alle sql statements har et resultat som blive //vist - fx. insert eller update echo '<b>ok</b>'; else { //lave en form hvos brugeren kan indtaste sql-statements echo '<form method=post action=admininterface.php?exec=1>'; echo '<textarea rows=8 cols=60 name=sqlstr nowarp></textarea><br>'; echo '<br><input type=submit value"indsend SQL">'; echo '</form>'; makepagefoot();?> answerquestions.php #!/usr/local/del1/datv-databaser/php/bin/php <?php /* Giver brugeren mulighed for at udfylde spørgeskemaer og sende svaret ind */ // database connect script. require 'db_connect.php'; require 'functions.php'; //Laver en dropdown til de options der kan være tilknyttet et spørgsmål //$intquestionid er id'en på spørgsmålet function makeoptiondropdown($intquestionid, $db) { makedropdown('option_'.$intquestionid,'option', 'name', 'optionid', 0, 48

49 'questionid='.$intquestionid, $db); echo '<br>'; //Laver en textbox hvor brugeren kan skrive sit svar //$intquestionid er id'en på spørgsmålet - dette brugeres kun i forbindelse //med updates function makequestiontextbox($intquestionid) { echo '<textarea name=text_'.$intquestionid.' cols=40 rows=8></textarea><br>'; //opdatere databasen med svaret på en option som brugeren har valgt //$intquestionid er id'en på spørgsmålet function updateoptiondropdown($intquestionid, $intcourseid) { if($_post['option_'.$intquestionid]!='') { $query = ("INSERT INTO answer (questionid, courseid, personid, optionid) VALUES (".$intquestionid.", ".$intcourseid.", ".$_SESSION['personID'].",".$_POST['option_'.$intQuestionID].")"); return $query; else return ''; //opdatere databasen med svaret som brugeren har indtastet //$intquestionid er id'en på spørgsmålet function updatequestiontextbox($intquestionid, $intcourseid) { $query = ("INSERT INTO answer (questionid, courseid, personid, answertext) VALUES (".$intquestionid.", ".$intcourseid.", ".$_SESSION['personID'].",'".sqlprep($_POST['text_'.$intQuestionID])."')"); return $query; //opdatere både option og text - stort set det samme som at kalde //updateoptiondropdown og updatequestiontextbox function updatequestionoptionandtextbox($intquestionid, $intcourseid) { if($_post['option_'.$intquestionid]!='') { $query = ("INSERT INTO answer (questionid, courseid, personid, optionid, answertext) VALUES (".$intquestionid.", ".$intcourseid.", ".$_SESSION['personID'].",".$_POST['option_'.$intQuestionID].",'".sqlprep($_POST['text_'.$intQuestionID])."')"); return $query; else return ''; makepagehead('udfyld spørgeskema', 'student'); if (isset($_get['answer'])) { //i det tilfælde hvor vi skal opdatere/indsætte brugerens svar $query = ("SELECT question.questionid, question.questiontypeid, question.name FROM question INNER JOIN course ON question.courseid=course.courseid WHERE course.courseid=".$_get['answer']." OR course.name='standard_sporgsmaal'"); $questions = pg_exec($db, $query); $numrows = pg_numrows($questions); //find hvilke spørgsmål brugeren har skulle svare på $trans=''; for($i=1; $i<=$numrows; $i++) { $question = pg_fetch_array($questions, $i-1); //hvilken type sprøgsmål/svar er der tale om if($question['questiontypeid']==1) { $trans=$trans.'; '.updateoptiondropdown($question['questionid'], $_GET['answer']); elseif($question['questiontypeid']==2) { $trans=$trans.'; '.updatequestiontextbox($question['questionid'], $_GET['answer']); else { $trans=$trans.'; '.updatequestionoptionandtextbox( $question['questionid'], $_GET['answer']); //Udfører alle updates, inserts og deletes som een samlet transaktion $trans='begin WORK;'.$trans.";COMMIT WORK;"; pg_exec($db, $trans); 49

50 echo 'Tak for hjælpen, dine svare er nu modtaget<br>'; if (isset($_get['courseid'])) { //vis de spørgsmål der hører til kurset med courseid $query = ("SELECT question.questionid, question.questiontypeid, question.name FROM question INNER JOIN course ON course.courseid=question.courseid WHERE course.courseid=".$_get['courseid']." OR course.name='standard_sporgsmaal' ORDER BY question.placement ASC"); $questions = pg_exec($db, $query); $numrows = pg_numrows($questions); echo '<form method=post action=answerquestions.php?answer='.$_get['courseid'].'>'; for($i=1; $i<=$numrows; $i++) { $question = pg_fetch_array($questions, $i-1); echo '<b>'.$i.'. - '.$question['name'].'</b><br>'; //hvilken type spørgsmål er det if($question['questiontypeid']==1) { makeoptiondropdown($question['questionid'], $db); elseif($question['questiontypeid']==2) { makequestiontextbox($question['questionid']); else { makeoptiondropdown($question['questionid'], $db); makequestiontextbox($question['questionid']); echo '<br>'; echo '<br><input type=submit value="indsend svar">'; echo '</form>'; else { //hent de kurser der har spørgsmål som brugeren ikke allerede har svaret på $query = ("SELECT DISTINCT course.courseid, course.name FROM course INNER JOIN question ON course.courseid=question.courseid INNER JOIN personcourse ON personcourse.courseid=course.courseid WHERE personcourse.personid=".$_session['personid']." AND course.name<>'standard_sporgsmaal' AND questionid NOT IN (SELECT questionid FROM answer WHERE personid=".$_session['personid'].") ORDER BY course.name ASC"); $courses = pg_exec($db, $query); $numrows = pg_numrows($courses); echo 'Vælg det fag du ønsker at udfylde et spørgeskema for'; echo '<table border=0>'; for($i=1; $i<=$numrows; $i++) { $course = pg_fetch_array($courses, $i-1); echo '<tr>'; echo '<td><a href=answerquestions.php?courseid='.$course['courseid'].'>'. $course['name'].'</a></td>'; echo '</tr>'; echo '</table>'; //hent kurser med spørgsmål der er svaret på $query = ("SELECT DISTINCT course.courseid, course.name FROM course INNER JOIN question ON course.courseid=question.courseid INNER JOIN personcourse ON personcourse.courseid=course.courseid WHERE personcourse.personid=".$_session['personid']." AND course.name<>'standard_sporgsmaal' AND questionid IN (SELECT questionid FROM answer WHERE personid=".$_session['personid'].") ORDER BY course.name ASC"); $courses = pg_exec($db, $query); $numrows = pg_numrows($courses); echo '<br><br>følgende fag har du allerede udfyldt et spørgeskema for'; echo '<table border=0>'; for($i=1; $i<=$numrows; $i++) { $course = pg_fetch_array($courses, $i-1); echo '<tr>'; echo '<td>'.$course['name'].'</a></td>'; echo '</tr>'; echo '</table>'; 50

51 makepagefoot();?> create_course.php #!/usr/local/del1/datv-databaser/php/bin/php <?php /* Opretter og redigere kurser */ // database connect script. require 'db_connect.php'; require 'functions.php'; makepagehead('opret kursus', 'teacher'); //hvis vi skal opdatere et kursus if (isset($_get['updateid'])) { $query = ("UPDATE course SET name='".sqlprep($_post['coursename'])."' WHERE courseid=".$_get['updateid']); pg_exec($db, $query); //vi skal lave et nyt kursus if (isset($_get['new'])) { $query = ("INSERT INTO course (name, personid) VALUES ('".sqlprep($_post['coursename'])."', ".$_SESSION['personID'].")"); pg_exec($db, $query); //et kursus skal slettes if (isset($_get['deleteid'])) { $query = ("DELETE FROM course WHERE courseid=".$_get['deleteid']); pg_exec($db, $query); //vi vil redigere et kursus der findes if (isset($_get['courseid'])) { $query = ("SELECT * FROM course WHERE courseid=".$_get['courseid']); $courses = pg_exec($db, $query); $course = pg_fetch_array($courses,0); if ($course) { echo '<form action=create_course.php?updateid='.$course['courseid']. ' method=post>'; echo 'Kursus navn: <input value="'.$course['name'].'" name=coursename><br>'; echo '<input type=submit value="opdater">'; echo '</form>'; //vi skal til at oprette et nyt kursus, dvs der skal indtastes oplysning //omkring kurset elseif (isset($_get['editnew'])) { echo '<form action=create_course.php?new=1 method=post>'; echo 'Kursus navn: <input value="" name=coursename><br>'; echo '<input type=submit value="opret">'; echo '</form>'; else { //vis alle kurser der findes $query = ("SELECT courseid, name FROM course ORDER BY name ASC"); $courses = pg_exec($db, $query); $numrows = pg_numrows($courses); //giver mulighed for at oprette nye kurser echo '<a href=create_course.php?editnew=1>opret nyt kursus</a><br><br>'; echo '<table border=0 width=500>'; for($i=1; $i<=$numrows; $i++) { $course = pg_fetch_array($courses, $i-1); echo '<tr>'; echo '<td width=400><a href=create_course.php?courseid='. $course['courseid'].'>'.$course['name'].'</a></td>'; echo '<td width=100><a href=create_course.php?deleteid='. $course['courseid'].'>[slet]</a></td>'; 51

52 echo '</tr>'; echo '</table>'; makepagefoot();?> createquestions.php #!/usr/local/del1/datv-databaser/php/bin/php <?php /* Giver læren mulighed for at oprette og redigere spørgsmål */ // database connect script. require 'db_connect.php'; require 'functions.php'; //lave de felter der er fælles for alle typer spørgsmål function inputquestion($strquestiontext, $intplacement) { echo 'Spørgsmål? <input type=text maxlength=200 name=questiontext value="'. $strquestiontext.'"><br>'; echo 'Placering? <input type=text maxlength=2 name=placement value="'. $intplacement.'"><br>'; //laver felterne til de evt. options der findes til et spørgsmål function inputoptions($intquestionid, $db) { $query = ("SELECT optionid, name FROM option WHERE questionid=".$intquestionid); $options = pg_exec($db, $query); $numrows = pg_numrows($options); for($i=1; $i<=$numrows; $i++) { $option = pg_fetch_array($options, $i-1); echo '<input type=text maxlength=50 name=option_'.$option['optionid']. ' value="'.$option['name'].'"><br>'; //laver knap til at tilføje nye optioner/valg echo '<input type=button value="tilføj option" onclick="javascript: submitform.action=submitform.action+\'&addnew=1\';submitform.submit();">'; //opdatere alle de optioner der findes til et givent spørgsmål function updateoptions($intquestionid, $db) { //finde hvilke optioner der er tale om $query = ("SELECT optionid, name FROM option WHERE questionid=".$intquestionid); $options = pg_exec($db, $query); $numrows = pg_numrows($options); for($i=1; $i<=$numrows; $i++) { $option = pg_fetch_array($options, $i-1); //opdatere felterne et ad gangen $query=("update option SET name='".sqlprep($_post['option_'. $option['optionid']])."' WHERE optionid=".$option['optionid']); pg_exec($db, $query); //sletter et spørgsmål if (isset($_get['deletequestionid'])) { $query = ("DELETE FROM question WHERE questionid=".$_get['deletequestionid']); pg_exec($db, $query); //opretter et nyt spørgsmål if(isset($_get['new'])) { $query = ("INSERT INTO question (courseid, questiontypeid, placement, name) VALUES (".$_GET['new'].",".$_POST['questiontype'].", ". $_POST['placement'].", '".sqlprep($_post['questiontext'])."')"); //vi finder id'en på det lige oprettede spørgsmål - name+courseid skal være unikt if(pg_exec($db, $query)!=false) { $query=("select questionid FROM question WHERE name='". sqlprep($_post['questiontext'])."' AND courseid=".$_get['new']); 52

53 $questions = pg_exec($db, $query); $question = pg_fetch_array($questions, 0); if(isset($_get['addnew'])) { //hvis der er ønske om at indsætte optioner $query=("insert INTO option (questionid, name) VALUES (".$question['questionid'].",'ny option')"); pg_exec($db, $query); //gå tilbage til den rigtige side redirect('createquestions.php?questionid='.$question['questionid']. '&courseid='.$_get['new']); //gå tilbage til den rigtige side redirect('createquestions.php?courseid='.$_get['new']); //opdater et spørgsmål if(isset($_get['updatequestion'])) { //opdater navn $query = ("UPDATE question SET placement=".$_post['placement'].", name='".sqlprep( $_POST['questiontext'])."' WHERE questionid=".$_get['updatequestion']); pg_exec($db, $query); //opdater optioner updateoptions($_get['updatequestion'], $db); if(isset($_get['addnew'])) { //ønsker vi samtidig at tilføje en ny option $query=("insert INTO option (questionid, name) VALUES (". $_GET['updatequestion'].",'Ny option')"); pg_exec($db, $query); //gå tilbage til den rigtige side redirect('createquestions.php?questionid='.$_get['updatequestion']. '&courseid='.$_get['courseid']); //gå tilbage til den rigtige side redirect('createquestions.php?courseid='.$_get['courseid']); makepagehead('opret spørgeskema', 'teacher'); //vi redigere et spørgsmåls der findes if (isset($_get['questionid'])) { echo '<form name=submitform method=post action=createquestions.php?updatequestion='. $_GET['questionid'].'&courseid='.$_GET['courseid'].'>'; $query=("select questiontypeid, name, placement FROM question WHERE questionid=".$_get['questionid']); $questions = pg_exec($db, $query); $question = pg_fetch_array($questions, 0); inputquestion($question['name'], $question['placement']); if($question['questiontypeid']!=2) { inputoptions($_get['questionid'], $db); echo '<input type=submit value="gem spørgsmål">'; echo '</form>'; //vi vil lave et nyt spørgsmål og skal derfor præsentere brugeren for de felter elseif (isset($_get['newquestion'])) { echo '<form name=submitform method=post action=createquestions.php?new='. $_GET['newquestion'].'>'; echo '<input type=hidden name=questiontype value="'.$_post['questiontype'].'">'; inputquestion('', 0); //er det et spørgsmål med optioner if($_post['questiontype']!=2) { inputoptions(0, $db); echo '<input type=submit value="opret spørgsmål">'; echo '</form>'; elseif (isset($_get['courseid'])) { //vis alle spørgsmål til et givnt kursus $query = ("SELECT * FROM question WHERE courseid=".$_get['courseid']." ORDER BY placement ASC"); 53

54 $questions = pg_exec($db, $query); $numrows = pg_numrows($questions); echo '<form method=post action=createquestions.php?newquestion='. $_GET['courseid'].'>'; makedropdown('questiontype','questiontype', 'name', 'questiontypeid', 0, '', $db); echo '<input type=submit value="opret nyt spørgsmål">'; echo '</form>'; for($i=1; $i<=$numrows; $i++) { $question = pg_fetch_array($questions, $i-1); echo '<a href=createquestions.php?questionid='.$question['questionid']. '&courseid='.$_get['courseid'].'>'.$question['name'].'</a>'; echo '<a href=createquestions.php?deletequestionid='.$question['questionid']. '&courseid='.$_get['courseid'].'> Slet</a><br>'; else { //viser alle kurser - dvs kurser der kan eller allerede er oprette spørgsmål for $query = ("SELECT course.courseid, course.name FROM course ORDER BY course.name ASC"); $courses = pg_exec($db, $query); $numrows = pg_numrows($courses); echo 'Vælg det fag du ønsker at oprette et spørgeskema for'; echo '<table border=0>'; for($i=1; $i<=$numrows; $i++) { $course = pg_fetch_array($courses, $i-1); echo '<tr>'; echo '<td><a href=createquestions.php?courseid='.$course['courseid'].'>'. $course['name'].'</a></td>'; echo '</tr>'; echo '</table>'; makepagefoot();?> db_connect.php <?php //connection til postgres databasen $db = pg_connect("host=grerr.diku.dk port=11275 dbname=k1db user=administrator password=gravko"); //vi bruger SESSION - derfor kalder vi session_start() på alle siderne session_start();?> default.php #!/usr/local/del1/datv-databaser/php/bin/php <?php /* Bruges kun som forside og til at skrive en kort beskrivelse */ // database connect script. require 'db_connect.php'; require 'functions.php'; makepagehead('velkommen', 'student'); echo 'Velkommen - i menuen til venstre kan du navigere gennem de forskellige muligheder du har'; makepagefoot();?> 54

55 functions.php <?php //sender brugeren videre til en anden side function redirect($url) { header("location: ".$URL); /* Redirect browser */ exit; ; //erstatter ' med '' for at undgå SQL fejl ved bruger indtastning af strenge function sqlprep($strsql) { return strtr($strsql, "'", "''"); //laver en dropdown boks på basis af data fra $strtable. //$strname er feltnavnet data skal hentes fra, $strid er iden der sendes videre ved POST //$intactiveid er id'en der default er aktiv //$strwhere kan indehold SQL kode for at begrænse indholdet i dropboksen function makedropdown($strdropdownname,$strtable, $strname, $strid, $intactiveid, $strwhere, $db) { if(strlen($strwhere)>0) $strwhere=' WHERE '.$strwhere.' '; $query = ("SELECT ".$strname.", ".$strid." FROM ".$strtable.$strwhere." ORDER BY ".$strname." ASC"); $rows = pg_exec($db, $query); $numrows = pg_numrows($rows); echo '<select name='.$strdropdownname.'>'; for($i=1; $i<=$numrows; $i++) { $row = pg_fetch_array($rows, $i-1); echo '<option '; if($intactiveid==$row[$strid]) echo 'selected '; echo 'value='.$row[$strid].'>'.$row[$strname].'</option>'; echo '</select>'; //laver en boks (udfoldet dropdown) på basis af data fra $strtable hvor brugeren kan vælge flere elementer. //$strname er feltnavnet data skal hentes fra, $strid er iden der sendes videre ved POST //$stractivetable er tablen der indholder data for hvilke af elemeterne der skal være valgt //$intactiveid er den id i stractivetable der skal begrænses på //$intactiveid er id'en der default er aktiv //$strwhere kan indehold SQL kode for at begrænse indholdet i dropboksen function makemultidropdown($strtable, $stractivetable, $strname, $strid, $stractiveid, $intactiveid, $db) { $query = ("SELECT ".$strtable.".".$strname.", ".$strtable.".".$strid.", ". $stractivetable.".".$strid." AS activeid FROM ".$strtable." LEFT OUTER JOIN ". $stractivetable." ON ".$strtable.".".$strid."=".$stractivetable.".".$strid." AND ".$stractivetable.".".$stractiveid."=".$intactiveid. " ORDER BY ".$strname." ASC"); $rows = pg_exec($db, $query); $numrows = pg_numrows($rows); echo '<select multiple size=8 name='.$stractivetable.'[]>'; for($i=1; $i<=$numrows; $i++) { $row = pg_fetch_array($rows, $i-1); echo '<option '; if(!is_null($row['activeid'])) echo 'selected '; echo 'value='.$row[$strid].'>'.$row[$strname].'</option>'; echo '</select>'; //Henter SQL strengen til at opdatere stractivetable fra makemultidropdown med de data brugeren har valgt function getupdatetablefrommultidropdownsql($arrids, $strtable, $stridname, $strfixedname, $intfixedid, $db) { //først sletter vi alle række som ikke længere er valgt af brugeren $strsqlwhere=''; $stror=''; for ($i=0; $i<count($arrids); $i++) { $strsqlwhere=$strsqlwhere.$stror.$stridname."=".$arrids[$i]; $stror=' OR '; if(strlen($strsqlwhere)>0) { $query = ("DELETE FROM ".$strtable. " WHERE ".$strfixedname."=".$intfixedid." AND NOT (".$strsqlwhere.")"); $trans=$query; for ($i=0; $i<count($arrids); $i++) { 55

56 //vi ser om række allerede findes, så skal den ikke indsættes igen $query = ("SELECT count(*) AS count FROM ".$strtable." WHERE ".$stridname."=".$arrids[$i]." AND ".$strfixedname."=".$intfixedid); $rows = pg_exec($db, $query); $row = pg_fetch_array($rows, 0); if($row['count']==0) { //hvis den ikke findes indsætter vi rækken $query = ("INSERT INTO ".$strtable." (".$stridname.", ".$strfixedname.") VALUES (".$arrids[$i].",".$intfixedid.")"); $trans=$trans.'; '.$query; return $trans; //updatere stractivetable fra makemultidropdown med de data brugeren har valgt function updatetablefrommultidropdown($arrids, $strtable, $stridname, $strfixedname, $intfixedid, $db) { //Udfører alle updates, inserts og deletes som een samlet transaktion $trans=getupdatetablefrommultidropdownsql($arrids, $strtable, $stridname, $strfixedname, $intfixedid, $db); $trans='begin WORK;'.$trans.";COMMIT WORK;"; pg_exec($db, $trans); function checklogin($strlogintype) { //checker om brugeren er logger ind - eller blive vedkommende sendt til //login siden if(!isset($_session['personid'])) { redirect('login.php'); //checker at bruger skal have adgang til siden //sikre at brugeren kunb får adgang til de sider han/hun har rettigheder til if($_session['usertype']=="student") { if($strlogintype!="student") die('du har ikke adgang til denne side'); elseif ($_SESSION['usertype']=="teacher") { if($strlogintype!="student" && $strlogintype!="teacher") die('du har ikke adgang til denne side'); ; //brugeren må være admin som har adgang til alt //laver menu til venstre på skærmen function makemenu() { echo '<br>'; echo '<div id=menu>'; if($_session['usertype']=='teacher' $_SESSION['usertype']=='admin') { echo '<a href=create_course.php>kurser</a><br>'; if($_session['usertype']=='admin') { echo '<a href=users.php>brugere</a><br>'; if($_session['usertype']=='student' $_SESSION['usertype']=='teacher' $_SESSION['usertype']=='admin') { echo '<a href=answerquestions.php>besvar spørgsmål</a><br>'; if($_session['usertype']=='teacher' $_SESSION['usertype']=='admin') { echo '<a href=createquestions.php>opret spørgsmål</a><br>'; if($_session['usertype']=='student' $_SESSION['usertype']=='teacher' $_SESSION['usertype']=='admin') { echo '<a href=viewanswers.php>se besvarelser</a><br>'; if($_session['usertype']=='admin') { echo '<a href=admininterface.php>admin interface</a><br>'; if($_session['usertype']=='student' $_SESSION['usertype']=='teacher' 56

57 $_SESSION['usertype']=='admin') { echo '<br><a href=logout.php>log af</a>'; echo '</div>'; //laver sidehovedet function makepagehead($strtitle, $strlogintype) { checklogin($strlogintype); echo '<html><head>'; echo '<link href="../stylesheet.css" type="text/css" rel="stylesheet">'; echo '<link rel="stylesheet" media="screen" type="text/css" href="../showhide.css">'; echo '<script src="../showhide.js" type="text/javascript"></script>'; echo "<title>".$strtitle."</title></head><body marginwidth=0 marginheight=0 onload='dhtml_menu_init();'>"; echo '<table border=0 cellspacing=0 cellpadding=0 width=100% height=100%> <tr><td bgcolor=#c6d1e6 colspan=3></td><td bgcolor=#c6d1e6><h1>'.$strtitle.'</h1></td><tr>'; echo '<tr><td bgcolor=#c6d1e6 colspan=3></td><td bgcolor=#c6d1e6> <small>logget på som: '.$_SESSION['personName'].'</small></td><tr>'; echo '<tr><td width=10 bgcolor=f4f4fe> </td><td width=150 height=100% valign=top bgcolor=#f4f4fe>'; makemenu(); echo '</td><td width=20> </td><td valign=top align=left><br>'; //laver sidefoden function makepagefoot() { echo '</td></tr>'; echo '</table>'; echo '</body></html>'; ;?> login.php #!/usr/local/del1/datv-databaser/php/bin/php <?php /* giver brugeren mulighed for at logge ind - sætter SESSION['personid'] */ // database connect script. require 'db_connect.php'; require 'functions.php'; if(isset($_session['personid'])) { //brugeren er logget ind! die('you are already logged in'); if (isset($_post['submit'])) { // if form has been submitted /* har brugeren udfyldt brugernavn + password */ if(!$_post['login']!$_post['passwd']) { die('you did not fill in a required field.'); //check at det er korrekt brugernavn+password $query = ("SELECT person.personid, person.name, persontype.typename FROM person INNER JOIN persontype ON persontype.persontypeid=person.persontypeid WHERE person.login = '".$_POST['login']."' AND person.password='".$_post['passwd']."'"); $check = pg_exec($db, $query); $numrows = pg_numrows($check); if (!$numrows) { //hvis check ikke er opfyldt! die('forkert brugernavn eller password.'); $info = pg_fetch_array($check,0); //vi gemmer brugerens id så vi kan bruge dette //på de andre sider + samt vi ved at brugeren er logget ind $_SESSION['personID']=$info['personid']; 57

58 $_SESSION['usertype']=$info['typename']; $_SESSION['personName']=$info['name']; pg_close($db);?> //send brugeren til vores default side redirect('default.php'); <html> <head> <title>login</title> </head> <body> <form action="<?php echo $_SERVER['PHP_SELF']?>" method="post"> <table align="center" border="1" cellspacing="0" cellpadding="3"> <tr><td>username:</td><td> <input type="text" name="login" maxlength="40"> </td></tr> <tr><td>password:</td><td> <input type="password" name="passwd" maxlength="50"> </td></tr> <tr><td colspan="2" align="right"> <input type="submit" name="submit" value="login"> </td></tr> </table> </form> </body> </html> logout.php #!/usr/local/del1/datv-databaser/php/bin/php <?php /* Giver brugeren mulighed for at udfylde spørgeskemaer og sende svaret ind */ // database connect script. require 'db_connect.php'; require 'functions.php'; $_SESSION['personName']=''; makepagehead('log ud', 'student'); unset($_session['personid']); echo 'Du er nu logget af!'; makepagefoot();?> showhide.css DIV#showhide h4 { cursor:pointer; cursor:hand; DIV#showhide div { display: none; showhide.js function browsercheck() { 58

59 this.ns4 = (document.layers)? true:false; this.ie = (document.all &&!window.opera)? true:false; this.ie4 = (document.all &&!document.getelementbyid)? true:false; this.iewin = (window.activexobject)? true:false; this.dom = (document.getelementbyid)? true:false; this.moz = (window.sidebar)? true:false; this.ns6 = (window.sidebar&&navigator.useragent.indexof('netscape')!=-1)? true:false; this.opera = (window.opera)? true:false; this.mac = (navigator.useragent.indexof('mac')!=-1)? true:false; this.iemac = ((navigator.useragent.indexof('mac')!=-1) && (document.all&&(!window.opera)) )? true:false; is = new browsercheck() if (is.dom &&!is.opera) { document.write('<link rel="stylesheet" media="screen" href="showhide.css">') var h4arr; function dhtml_menu_init(){ if (is.dom &&!is.opera) { var leftmenu = document.getelementbyid('showhide'); h4arr = leftmenu.getelementsbytagname('h4'); for (var i = 0; i < h4arr.length; i++) { if (is.ie) h4arr[i].onselectstart = function() {return false; h4arr[i].onclick = menuitemtoggle; function menuitemtoggle() { if (this.nextsibling.style.display!= "block") { //Reset all menus for (var i = 0; i < h4arr.length; i++) { h4arr[i].style.color = "black"; h4arr[i].style.background = "#cccccc"; h4arr[i].nextsibling.style.display = "none"; //Now set active link this.nextsibling.style.display = "block"; this.title = ""; this.style.color = "White"; this.style.background = "#666666"; function showall() { for (var i = 0; i < h4arr.length; i++) { h4arr[i].style.color = "white"; h4arr[i].style.background = "#666666"; h4arr[i].nextsibling.style.display = "block"; function hideall() { for (var i = 0; i < h4arr.length; i++) { h4arr[i].style.color = "black"; h4arr[i].style.background = "#cccccc"; h4arr[i].nextsibling.style.display = "none"; StyleSheet.css a:link { color: #000000; text-decoration: underline; a:active { color: #000000; text-decoration: underline; a:visited { color: #000000; text-decoration: underline; a:hover { color: darkblue; text-decoration: none; /* showhide */ DIV#showhide h4 { font: 11px Arial, Helvetica, Verdana, sans-serif; font-weight: bold; margin: 0px 0px 0px 0px; 59

60 padding: 2px 5px 2px 5px; background: #CCCCCC; border-bottom: solid 1px #666666; DIV#showhide h4.highlight { background: #666666; color: #FFFFFF; DIV#showhide h4 A:link { color: #000000; text-decoration: none; DIV#showhide h4 A:visited { color: #000000; text-decoration: none; DIV#showhide h4 A:active { color: #000000; text-decoration: none; DIV#showhide h4 A:hover { color: #FFFFFF; text-decoration: none; DIV#showhide h4 A.highlight:link { color: #FFFFFF; text-decoration: none; DIV#showhide h4 A.highlight:visited { color: #FFFFFF; text-decoration: none; DIV#showhide h4 A.highlight:active { color: #FFFFFF; text-decoration: none; DIV#showhide h4 A.highlight:hover { color: #FFFFFF; text-decoration: none; /* Body */ body { margin: 0px 0px 0px 0px; background-color: #f4f4f4; font: 11px Arial, Helvetica, Verdana, sans-serif; color: #000000; padding: 0px; h1 { font: 36px Arial, Helvetica, Verdana, sans-serif; img, table { border: black solid 0px; td { font: 11px Arial, Helvetica, Verdana, sans-serif; users.php #!/usr/local/del1/datv-databaser/php/bin/php <?php /* Giver mulighed for at administrere brugere og de kurser de tager */ // database connect script. require 'db_connect.php'; require 'functions.php'; makepagehead('opret bruger', 'admin'); //vi skal opdatere oplysninger om en bruger if (isset($_get['updateid'])) { $query = ("UPDATE person SET name='".sqlprep($_post['username']). "', persontypeid=".$_post['persontype']. ", login='".sqlprep($_post['login']). "', password='".sqlprep($_post['password'])."' WHERE personid=".$_get['updateid']); //opdater hvilke kurser brugeren tager $trans=$query.'; '.getupdatetablefrommultidropdownsql($_post['personcourse'], 'personcourse', 'courseid', 'personid', $_GET['updateid'], $db); $trans='begin WORK;'.$trans.";COMMIT WORK;"; pg_exec($db, $trans); if (isset($_get['new'])) { //opret bruger $query = ("INSERT INTO person (name, persontypeid, login, password) VALUES ('".sqlprep($_post['username'])."',".$_post['persontype']. ",'".sqlprep($_post['login'])."','".sqlprep($_post['password'])."')"); //hvis brugeren er oprettet korrekt, så hent id på brugeren (login+password er altid unikt) //og tilknyt kurser på baggrund af id'en //I dette tilfælde mangler transaktionsstyring! if(pg_exec($db, $query)!=false) { //hent id på den netop oprettede bruger $query=("select personid FROM person WHERE login='".sqlprep($_post['login']). "' AND password='".sqlprep($_post['password'])."'"); $users = pg_exec($db, $query); $user = pg_fetch_array($users,0); 60

61 //tilknyt kurser updatetablefrommultidropdown($_post['personcourse'], 'personcourse', 'courseid', 'personid', $user['personid'], $db); //slet en bruger if (isset($_get['deleteid'])) { $query = ("DELETE FROM person WHERE personid=".$_get['deleteid']); pg_exec($db, $query); //vi skal redigere en bruger if (isset($_get['personid'])) { $query = ("SELECT * FROM person WHERE personid=".$_get['personid']); $courses = pg_exec($db, $query); $course = pg_fetch_array($courses,0); if ($course) { echo '<form action=users.php?updateid='.$course['personid'].' method=post>'; echo '<table border=0 width=400>'; echo '<tr><td width=150>brugerens navn:</td><td colspan=250><input value="'. $course['name'].'" name=username></td></tr>'; echo '<tr><td width=150>bruger type:</td><td width=250>'; //vis en dropdown med bruger typer makedropdown('persontype', 'persontype','typename','persontypeid',$course['persontypeid'],'',$db); echo '</td></tr>'; echo '<tr><td width=150>login navn:</td><td width=250><input value="'. $course['login'].'" name=login></td></tr>'; echo '<tr><td width=150>password:</td><td width=250><input type=password value="'. $course['password'].'" name=password></td></tr>'; echo '<tr><td colspan=2 width=400>til knyttet følgende kurser:</td></tr>'; //vis kurser og hvilke kurser brugeren tager echo '<tr><td colspan=2 width=400>'; makemultidropdown('course', 'personcourse', 'name', 'courseid', 'personid', $course['personid'], $db); echo '</td></tr>'; echo '<tr><td colspan=2 width=400><input type=submit value="opdater"></td></tr>'; echo '</table>'; echo '</form>'; //vi skal oprette en ny bruger - derfor gives der mulighed for at indtaste korrekte data elseif (isset($_get['editnew'])) { echo '<form action=users.php?new=1 method=post>'; echo '<table border=0 width=400>'; echo '<tr><td width=150>brugerens navn:</td><td width=250><input value="" name=username></td></tr>'; echo '<tr><td width=150>bruger type:</td><td width=250>'; makedropdown('persontype','persontype','typename','persontypeid',0,'',$db); echo '</td></tr>'; echo '<tr><td width=150>login navn:</td><td width=250><input value="ny_bruger" name=login></td></tr>'; echo '<tr><td width=150>password:</td><td><input type=password value="" name=password></td></tr>'; echo '<tr><td width=400 colspan=2>til knyttet følgende kurser:</td></tr>'; echo '<tr><td width=400 colspan=2>'; makemultidropdown('course', 'personcourse', 'name', 'courseid', 'personid', 0, $db); echo '</td></tr>'; echo '<tr><td width=400 colspan=2><input type=submit value="opret"></td></tr>'; echo '</table>'; echo '</form>'; else { //vis alle oprettede brugere $query = ("SELECT name, personid FROM person ORDER BY name ASC"); $courses = pg_exec($db, $query); $numrows = pg_numrows($courses); //giv mulighed for at oprette nye brugere echo '<a href=users.php?editnew=1>opret ny bruger</a><br><br>'; echo '<table border=0 width=500>'; for($i=1; $i<=$numrows; $i++) { $course = pg_fetch_array($courses, $i-1); echo '<tr>'; echo '<td width=400><a href=users.php?personid='.$course['personid'].'>'.$course['name'].'</a></td>'; echo '<td width=100><a href=users.php?deleteid='.$course['personid'].'>[slet]</a></td>'; echo '</tr>'; echo '</table>'; makepagefoot();?> 61

62 viewanswers.php #!/usr/local/del1/datv-databaser/php/bin/php <?php /* Giver en lærer mulighed for at se de svar brugeren har indsendt */ // database connect script. require 'db_connect.php'; require 'functions.php'; makepagehead('se besvarelser', 'student'); //hent statistik på options for et givent spørgsmål function getoptionstats($intquestionid, $db) { //hent antal svar for det givne spørgsmål $query=("select COUNT(option.optionid) AS count FROM answer INNER JOIN option ON answer.optionid=option.optionid WHERE option.questionid=".$intquestionid); $counter = pg_exec($db, $query); $count = pg_fetch_array($counter, 0); $inttotalcount=$count['count']; $query=("select COUNT(answer.optionid) as count, option.name FROM option LEFT OUTER JOIN answer ON option.optionid=answer.optionid WHERE (option.questionid=".$intquestionid.") OR (answer.optionid IS NULL AND option.questionid=".$intquestionid.") GROUP BY option.optionid, option.name"); //UNION //(SELECT 0 AS count, option.name FROM option //WHERE option.questionid=".$intquestionid." AND )"); $stats = pg_exec($db, $query); $numrows = pg_numrows($stats); for($i=1; $i<=$numrows; $i++) { $stat = pg_fetch_array($stats, $i-1); if($inttotalcount==0) { $fltprocent=0.0; else { $fltprocent=floatval($stat['count'])/floatval($inttotalcount)*100; echo '<table align=left border=0 width=100 height=10> <tr><td bgcolor=#00ff00 width='.$fltprocent.'%></td> <td bgcolor=#ff0000 width='.floatval(100-floatval($fltprocent)).'%> </td></tr></table>'; echo $stat['name'].': '.round($fltprocent).'%<br>'; function showanswers($intquestionid, $db) { $query=("select answertext FROM answer WHERE questionid=".$intquestionid); $answers = pg_exec($db, $query); $numrows = pg_numrows($answers); for($i=1; $i<=$numrows; $i++) { $answer = pg_fetch_array($answers, $i-1); echo '<h4>'.$i.'. svar:</h4>'; echo '<div>'; echo $answer['answertext']; echo '</div>'; if(isset($_get['courseid'])) { $query=("select COUNT(DISTINCT answer.personid) FROM answer WHERE answer.courseid=".$_get['courseid']); $answercounts = pg_exec($db, $query); 62

63 $answercount = pg_fetch_array($answercounts, 0); echo 'Der er '.$answercount['count']. ' der har besvaret spørgsmålene indtil videre<br>'; //hent alle spørgsmål for et givent kursus - udfra disse kan vi finde svarende $query = ("SELECT question.questionid, question.questiontypeid, question.name FROM question INNER JOIN course ON question.courseid=course.courseid WHERE course.courseid=".$_get['courseid']." OR course.name='standard_sporgsmaal' ORDER BY question.placement ASC"); $answers = pg_exec($db, $query); $numrows = pg_numrows($answers); echo '<br>[<a href="javascript:showall();">vis alle tekst-svar</a>] [<a href="javascript:hideall();">skjul alle tekst-svar</a>]<br>'; echo '<div id="showhide">'; for($i=1; $i<=$numrows; $i++) { $answer = pg_fetch_array($answers, $i-1); echo '<br><b>'.$i.'. - '.$answer['name'].':</b><br>'; if($answer['questiontypeid']==1) { getoptionstats($answer['questionid'], $db); elseif($answer['questiontypeid']==2) { showanswers($answer['questionid'], $db); else { getoptionstats($answer['questionid'], $db); echo '<br>'; showanswers($answer['questionid'], $db); echo '</div>'; else { //hent alle kurser hvor der er lavet spørgsmål til $query = ("SELECT DISTINCT course.courseid, course.name FROM course INNER JOIN question ON question.courseid=course.courseid WHERE course.name<>'standard_sporgsmaal' ORDER BY course.name ASC"); $answers = pg_exec($db, $query); $numrows = pg_numrows($answers); echo 'Vælg det fag du ønsker at se besvarelser for:<br><br>'; for($i=1; $i<=$numrows; $i++) { $answer = pg_fetch_array($answers, $i-1); echo '<a href=viewanswers.php?courseid='.$answer['courseid'].'>'. $answer['name'].'</a><br>'; makepagefoot();?> 63

PHP Snippets. De små korte. Skrevet af Daniel Pedersen

PHP Snippets. De små korte. Skrevet af Daniel Pedersen PHP Snippets De små korte Skrevet af Daniel Pedersen Indhold PHP Snippets De små korte er en samling af små og praktiske kode eksempler med kort forklaring, som med formål at kunne benyttes til opsalgsværk

Læs mere

Begrænsninger i SQL. Databaser, efterår 2002. Troels Andreasen

Begrænsninger i SQL. Databaser, efterår 2002. Troels Andreasen Databaser, efterår 2002 Begrænsninger i SQL Troels Andreasen Datalogiafdelingen, hus 42.1 Roskilde Universitetscenter Universitetsvej 1 Postboks 260 4000 Roskilde Telefon: 4674 2000 Fax: 4674 3072 www.dat.ruc.dk

Læs mere

Indholdsfortegnelse Databaser og PHP... 3 Opgave... 4 Opgave... 5 Opgave... 6 Sidste opgave er en lille gæstebog... 7 Kilder og nyttige links:...

Indholdsfortegnelse Databaser og PHP... 3 Opgave... 4 Opgave... 5 Opgave... 6 Sidste opgave er en lille gæstebog... 7 Kilder og nyttige links:... Indholdsfortegnelse Databaser og PHP... 3 Opgave... 4 Opgave... 5 Opgave... 6 Sidste opgave er en lille gæstebog... 7 Kilder og nyttige links:... 9 Nogle HTML tags... 9 Databaser og PHP Når vi snakker

Læs mere

Tagwall med Php & MySQL

Tagwall med Php & MySQL Denne guide er oprindeligt udgivet på Eksperten.dk Tagwall med Php & MySQL Her laver vi en tagwall i Php & MySQL... jeg forklarer dog ikke så meget, men jeg håber du kan få det til at blive til en tagwall

Læs mere

Eksamen, DSDS, efterår 2007

Eksamen, DSDS, efterår 2007 Eksamen, DSDS, efterår 2007 Introduktion til Scripting, Databaser og Systemarkitektur Jonas Holbech og Martin Elsman IT Universitetet i København 7. januar 2008 Alle hjælpemidler er tilladte, dog ikke

Læs mere

The Design Diaries Project 3 2. Semester. Blog om designprincipper

The Design Diaries Project 3 2. Semester. Blog om designprincipper The Design Diaries Project 3 2. Semester Blog om designprincipper By Lif Neergaard www.lifmediadesign.dk [email protected] Mathias Larsen www.nefjam.dk [email protected] Ida Christensen www.idamedia.dk

Læs mere

Bemærk! Et PHP script har kun brug for at forbinde én gang til databaseserveren. Det kan så sagtens udføre flere kommandoer vha. denne forbindelse.

Bemærk! Et PHP script har kun brug for at forbinde én gang til databaseserveren. Det kan så sagtens udføre flere kommandoer vha. denne forbindelse. Mysqli Webintegrator Når vi arbejder med server-side scripting ( i vort tilfælde PHP), har vi ofte behov for at kunne tilgå data, som vi opbevarer i en database. Det kan f.eks. dreje sig om nyhederne i

Læs mere

En Kort Introduktion til Oracle

En Kort Introduktion til Oracle En Kort Introduktion til Oracle Henrik Bulskov 12. februar 2001 [email protected] 1 Start SQL*Plus... 1 1.1 TELNET... 1 1.2 WINDOWS SQL PLUS... 2 2 Kør et SQL-script... 3 3 Hjælp i SQL*Plus... 3 4 Editering

Læs mere

Databaseadgang fra Java

Databaseadgang fra Java Databaseadgang fra Java Grundlæggende Programmering med Projekt Peter Sestoft Fredag 2007-11-23 Relationsdatabasesystemer Der er mange databaseservere Microsoft Access del af Microsoft Office MySQL god,

Læs mere

Views etc. Databaser

Views etc. Databaser Views etc. Databaser Views Med Views kan vi gemme nogle af de lange select sætninger. I vores eksempel fra tidligere er det f.eks. forbundet med en del besvær at finde telefon nr og bilmærker for en sælger

Læs mere

PHP kode til hjemmeside menu.

PHP kode til hjemmeside menu. PHP kode til hjemmeside menu. Home Hovedmenu 1 Hovedmenu 2 Hovedmenu 3 Hovedmenu 4 Undermenu 1 Breadcrumb Her vises indholdet af den valgte side Undermenu 2 Undermenu 3 Undermenu 4 Evt. en mulighed for

Læs mere

De vigtigste SQL-sætninger. SQL kap Oprette database. DDL og DML

De vigtigste SQL-sætninger. SQL kap Oprette database. DDL og DML SQL kap 6-7 + 17-20 DDL og DML 1 De vigtigste SQL-sætninger Data Definition Language (DDL) create table: opretter en ny tabel create unique index: tilføjer et index til en tabel drop table : sletter en

Læs mere

Indholdsfortegnelse. EasyIQ IDM 5.4 Brugermanual

Indholdsfortegnelse. EasyIQ IDM 5.4 Brugermanual Indholdsfortegnelse Indledning... 2 Forsiden... 2 Dine genveje... 3 Nyheder... 3 EasyIQ og EasyIQ Quick Funktioner... 3 Administration... 8 Licens... 8 Nyheder... 9 Eksterne links... 11 Log... 12 Password...

Læs mere

BRUGER KURSUS RAMBØLL HJEMMESIDE

BRUGER KURSUS RAMBØLL HJEMMESIDE Til Forsyningsvirksomheder i Danmark Dokumenttype Brugervejledning Rambøll Hjemmeside Full Responsive Dato Oktober 2017 BRUGER KURSUS RAMBØLL HJEMMESIDE BRUGER KURSUS RAMBØLL HJEMMESIDE Revision 01 Dato

Læs mere

Introduktion til SQL queries

Introduktion til SQL queries Denne guide er oprindeligt udgivet på Eksperten.dk Introduktion til SQL queries Denne artikel beskriver nogle forskellige muligheder i SQL queries. Eksemplerne skulle gerne være standard SQL og virke i

Læs mere

Introduktion til Oracle, Datalogi, RUC Af: Jens Lauterbach ([email protected]) 2002

Introduktion til Oracle, Datalogi, RUC Af: Jens Lauterbach (jeans@ruc.dk) 2002 Introduktion til Oracle, Datalogi, RUC Af: Jens Lauterbach ([email protected]) 2002 På datalogi har vi en databaseserver, som de studerende på datalogi kan benytte til projekter og som også benyttes i forbindelse

Læs mere

En opsamling af artefakter for Hotel Databasen som REST-service Bygger på Hotel opgaven i 8 trin

En opsamling af artefakter for Hotel Databasen som REST-service Bygger på Hotel opgaven i 8 trin En opsamling af artefakter for Hotel Databasen som REST-service Bygger på Hotel opgaven i 8 trin Trin 1: Lav en Domain model Opgave beskrivelse - Scandic hotel kæde Lav en domain model af Hotel-kæden.

Læs mere

DATABASE Projekt 1-3. semester

DATABASE Projekt 1-3. semester DATABASE Projekt 1-3. semester Gruppe 2- CLmul-a12e Projekt URL http://www.lucasperch.dk/projekter/database.pdf Gruppe 2 Lucas Perch-Nielsen [email protected] http://lucasperch.dk/skole.php Niclas

Læs mere

De skjulte input typer:

De skjulte input typer: Hvis man skal lave en html formular er der nogle felter til rådighed som kan benyttes, alt efter hvad output fra formularen skal være. Det felt som alle andre felter skal omkranses af er form tagget, som

Læs mere

Data lagring. 2. iteration (implement backend)

Data lagring. 2. iteration (implement backend) Data lagring 2. iteration (implement backend) Emner Grundlæggende database begreber. Data definitionskommandoer ER-diagrammer og cardinalitet/relationer mellem tabeller Redundant data og Normalisering

Læs mere

Eksamen, DSDS, efterår 2008

Eksamen, DSDS, efterår 2008 Eksamen, DSDS, efterår 2008 Introduktion til Scripting, Databaser og Systemarkitektur Jonas Holbech IT Universitetet i København 6. januar 2009 Alle hjælpemidler er tilladte, dog ikke computer og kommunikationsmidler.

Læs mere

PHP 3 UGERS FORLØB PHP, MYSQL & SQL

PHP 3 UGERS FORLØB PHP, MYSQL & SQL PHP 3 UGERS FORLØB PHP, MYSQL & SQL Uge 1 & 2 Det basale: Det primære mål efter uge 1 og 2, er at få forståelse for hvordan AMP miljøet fungerer i praksis, og hvordan man bruger PHP kodesproget til at

Læs mere

Procesbeskrivelse - Webprogrammering

Procesbeskrivelse - Webprogrammering Procesbeskrivelse - Webprogrammering Indholdsfortegnelse Forudsætninger... 1 Konceptet... 2 Hjemmesiden... 2 Server-side... 3 Filstrukturen... 3 Databasehåndtering og serverforbindelse... 4 Client-side...

Læs mere

Eksempel på en database: studenter, kurser, eksamener

Eksempel på en database: studenter, kurser, eksamener Udvidet Programmering 1999 Forelæsning 20, fredag 12. november 1999 Relationsdatabaser: relationer, tupler, attributter Forespørgselssproget SQL Databasesystemet PostgreSQL Tilgang til relationsdatabaser

Læs mere

Kursusbeskrivelse. Forarbejde. Oprettelse af en Access-database

Kursusbeskrivelse. Forarbejde. Oprettelse af en Access-database Kursusbeskrivelse Oprettelse af en Access-database Som eksempel på en Access-database oprettes en simpelt system til administration af kurser. Access-databasen skal indeholde: et instruktørkartotek et

Læs mere

Sådan kan du sende data fra din egen hjemmeside til JitBesked via en HTML-JDF.

Sådan kan du sende data fra din egen hjemmeside til JitBesked via en HTML-JDF. Sådan kan du sende data fra din egen hjemmeside til JitBesked via en HTML-JDF. Vejledningen her beskriver hvordan man opbygger en form i HTML og sender indholdet af felterne til JitBesked. Det kræver du

Læs mere

Projekt Database, Gruppe 4A. Projekt 1, 3. Semester D A T A B A S E. Klasse MulA13 Gruppenummer: A4

Projekt Database, Gruppe 4A. Projekt 1, 3. Semester D A T A B A S E. Klasse MulA13 Gruppenummer: A4 Projekt Database, Gruppe 4A 0 Projekt 1, 3. Semester D A T A B A S E Klasse MulA13 Gruppenummer: A4 Projekt Database, Gruppe 4A 1 Fakta-ark Klasse MulA13, Gruppenummer: A4 Gruppemedlemmer: Amalie Ardahl

Læs mere

Gem dine dokumenter i BON s Content Management System (CMS)

Gem dine dokumenter i BON s Content Management System (CMS) 24. august 2007 Gem dine dokumenter i BON s Content Management System (CMS) INDHOLDSFORTEGNELSE 1. Indledning... 2 2. Se indholdet i dit Content Management System... 3 3. Tilgå dokumenterne i My Content

Læs mere

My booking. Generelt. Forsiden. Version 9.0

My booking. Generelt. Forsiden. Version 9.0 My booking Version 9.0 System til at lave online bookinger, med mulighed for opdeling i grupper, forskellige booking typer, ændre layout indstillinger, status styring, sprogvalg samt en del mere, detaljer

Læs mere

Web Admin 5.5. Brugsvejledning for User admin. Copyright 2003 Gullestrup.net

Web Admin 5.5. Brugsvejledning for User admin. Copyright 2003 Gullestrup.net Web Admin 5.5 Copyright 2003 Gullestrup.net Log ind på systemet Start med at gå ind på http://mailadmin.gullestrup.net i din browser. Indtast din Email Adresse samt Password, som hører til din konto, tryk

Læs mere

Opsætning af brugere og temaer i GIS4Mobile

Opsætning af brugere og temaer i GIS4Mobile Opsætning af brugere og temaer i GIS4Mobile Brugerne og deres adgang til data konfigureres gennem et webinterface, som nås via dette link: http://www.geosms.dk/g4m_websetup Grundlæggende skal det fremhæves

Læs mere

FSFIs lynguide til DFRs elektronisk bevissystem

FSFIs lynguide til DFRs elektronisk bevissystem FSFIs lynguide til DFRs elektronisk bevissystem Dette er en kort guide i anvendelsen af Dansk Førstehjælpsråd elektroniske bevissystem. Guiden viser og forklarer hvordan du som instruktør og medlem af

Læs mere

Indhold. Indholdsfortegnelse

Indhold. Indholdsfortegnelse Indholdsfortegnelse Indhold Indledning... 2 Forsiden... 2 Dine genveje... 3 Nyheder... 3 EasyIQ og EasyIQ Quick Funktioner... 3 Administration... 6 Licens... 7 Nyheder... 8 Log... 9 Password... 9 System...

Læs mere

FSFI s guide til DFR s elektronisk bevissystem

FSFI s guide til DFR s elektronisk bevissystem FSFI s guide til DFR s elektronisk bevissystem Dette er en kort guide i anvendelsen af Dansk Førstehjælpsråd elektroniske bevissystem. Guiden viser og forklarer, hvordan du som instruktør og medlem af

Læs mere

Gæstebog med validering opbygget med MySQL

Gæstebog med validering opbygget med MySQL Denne guide er oprindeligt udgivet på Eksperten.dk Gæstebog med validering opbygget med MySQL Dette er en simpel gæstebog, som kan hjælpe folk med at lave en velfungerende gæstebog uden alt for meget arbejde.

Læs mere

DB undervisning 01-01

DB undervisning 01-01 Databaser... 2 Tabeller... 2 Redundans... 3 Første regel... 4 Anden regel... 4 Tredje regel... 5 Relationer... 5 Opskrift... 6 SQL sætninger til at oprette tabeller... 7 SQL sætninger til at indsætte data...

Læs mere

Øvelse 9. Klasser, objekter og sql-tabeller insert code here

Øvelse 9. Klasser, objekter og sql-tabeller insert code here Øvelse 9. Klasser, objekter og sql-tabeller Denne opgave handler om hvordan man opbevarer data fra databasekald på en struktureret måde. Den skal samtidig give jer erfaringer med objekter, der kommer til

Læs mere

Database. lv/

Database. lv/ Database 1 Database Design Begreber 1 Database: En fælles samling af logiske relaterede data (informationer) DBMS (database management system) Et SW system der gør det muligt at definer, oprette og vedligeholde

Læs mere

OpenTele datamonitoreringsplatform

OpenTele datamonitoreringsplatform OpenTele datamonitoreringsplatform Brugergrænsefladedokumentation 1. maj 2013 Indholdsfortegnelse Indholdsfortegnelse...2 Indledning...3 Brugergrænseflade for OpenTele-server...3 Administrationsfunktionalitet...3

Læs mere

EVALUERING I SURVEYXACT TRIN FOR TRIN

EVALUERING I SURVEYXACT TRIN FOR TRIN EVALUERING I SURVEYXACT TRIN FOR TRIN LÆR AT TACKLE 2015 KOMITEEN FOR SUNDHEDSOPLYSNING 1 INDLEDNING Komiteen for Sundhedsoplysning stiller SurveyXact et internetbaseret redskab til kvalitetssikring til

Læs mere

Indholdsfortegnelse If-sætningen... 3 Opgaver... 4 OR, AND sammen med if-sætningen... 5 Rand() funktion... 5 Opgave... 5 Include() funktionen...

Indholdsfortegnelse If-sætningen... 3 Opgaver... 4 OR, AND sammen med if-sætningen... 5 Rand() funktion... 5 Opgave... 5 Include() funktionen... Modul 2 Indholdsfortegnelse If-sætningen... 3 Opgaver... 4 OR, AND sammen med if-sætningen... 5 Rand() funktion... 5 Opgave... 5 Include() funktionen... 6 Opgave... 6 POST/GET og formular... 6 Opgaver...

Læs mere

Manual Version 2. til oprettelse af hjemmesider for landsbyer i Rebild kommune

Manual Version 2. til oprettelse af hjemmesider for landsbyer i Rebild kommune Manual Version 2 til oprettelse af hjemmesider for landsbyer i Rebild kommune Oversigt: Login Hjemmeside...... side 3 Login Administrationsmodul... side 5 Kategorier.. side 6 Opret/rediger første side...

Læs mere

Web Admin 5.5. Brugsvejledning for Domain admin. Copyright 2003 Gullestrup.net

Web Admin 5.5. Brugsvejledning for Domain admin. Copyright 2003 Gullestrup.net Web Admin 5.5 Copyright 2003 Gullestrup.net Log ind på systemet Start med at gå ind på http://mailadmin.gullestrup.net i din browser. Indtast din Email Adresse samt Password, som du tidligere har modtaget

Læs mere

FORCE Inspect Online Manual v. 1.02. FORCE Inspect Online Manual. 1 af 18

FORCE Inspect Online Manual v. 1.02. FORCE Inspect Online Manual. 1 af 18 FORCE Inspect Online Manual 1 af 18 Indholdsfortegnelse Indholdsfortegnelse... 2 FORCE Inspect Online Manual... 3 Generelt... 3 Login... 3 Main... 4 Intro sektion... 4 Links sektion... 4 News sektion...

Læs mere

September 2012 VEJLEDNING. Kursustilmelding via BL.dk

September 2012 VEJLEDNING. Kursustilmelding via BL.dk September 2012 VEJLEDNING Kursustilmelding via BL.dk Indhold Indledning... 3 Login og find kursus... 4 Tilmeldingsbilledet... 9 Håndtering af kursusdeltagere... 11 Opret ny kursusdeltager... 11 Tilmelding

Læs mere

Dokumentation. Udbyder : sms1919.dk Service : sms-grupper Static FBML Facebook. : Facebook Integration med sms-grupper.

Dokumentation. Udbyder : sms1919.dk Service : sms-grupper Static FBML Facebook. : Facebook Integration med sms-grupper. Dokumentation Udbyder : sms1919.dk Service : sms-grupper Static FBML Facebook Moduler Påkrævet : Facebook Integration med sms-grupper Version : v1.00 Indholdsfortegnelse Versionshistorik... 3 Målet med

Læs mere

Brugermanual PoP3 og Outlook Office 2003 Webmail www.321mail.dk. Udarbejdet af IT-afdelingen 2005

Brugermanual PoP3 og Outlook Office 2003 Webmail www.321mail.dk. Udarbejdet af IT-afdelingen 2005 Brugermanual PoP3 og Outlook Office 2003 Webmail www.321mail.dk Udarbejdet af IT-afdelingen 2005 Indholdsfortegnelse 1. INDLEDNING... 4 2. OUTLOOK 2003... 4 3. BRUGERVEJLEDNING I BRUGEN AF WEB MAIL...

Læs mere

Listen over reserverede ord er meget lang, men de væsentligste vil jeg beskrive her i denne artikel:

Listen over reserverede ord er meget lang, men de væsentligste vil jeg beskrive her i denne artikel: Denne guide er oprindeligt udgivet på Eksperten.dk SQL og ASP En artikel omkring simpel SQL og hvordan disse opbygges, udformes og udføres, sådan at man kan få et brugbart resultat i ASP. Dette ligefra

Læs mere

OBS! Hvis du skal oprette en bruger på din kundes aftale, skal du bruge den vejledning, som du finder længere nede i dette dokument.

OBS! Hvis du skal oprette en bruger på din kundes aftale, skal du bruge den vejledning, som du finder længere nede i dette dokument. Når du skal oprette en ny bruger på din lønpartneraftale, starter du på forsiden af DataLøn, hvor du i topmenuen vælger Opsætning og klikker på Brugeradministration. Herefter skal du vælge Mine brugere

Læs mere

Vejledning Tabeller (data tabeller)

Vejledning Tabeller (data tabeller) . Vejledning Tabeller (data tabeller) Datatabeller vs. Layouttabeller Beskrivelse af en tilgængelig datatabel Opret en tilgængelig (simpel) tabel indsæt eller fjern en række eller kolonne Indsæt spænd

Læs mere

www.evalueringssystem.dk

www.evalueringssystem.dk Brugervejledning Indledning... 3 Log på evalueringssystemet... 4 Afprøv en evaluering... 8 Åbn en evaluering eller en øvelse... 10 Gennemfør en evaluering og en øvelse... 13 Luk en evaluering... 15 Se

Læs mere

Database "opbygning"

Database opbygning Database "opbygning" Dette områder falder mest under en DBA's ansvarsområde. Det kan sagtens tænkes at en database udvikler i nogle situationer vil blive nød til at oprette produktions og test) databaser,

Læs mere

Jysk Online Medie ApS - Vestergade 32, 8600 Silkeborg - Tlf.:

Jysk Online Medie ApS - Vestergade 32, 8600 Silkeborg - Tlf.: Brugervejledning til hjemmeside Kristian Kalajdzic Denne vejledning har til formål at hjælpe dig til at tilgå, vedligeholde og benytte din hjemmeside. Vejledningen henvender sig til hjemmesider bygget

Læs mere

Indholdsfortegnelse Opret engelsk version af hjemmesiden... 2

Indholdsfortegnelse Opret engelsk version af hjemmesiden... 2 Indholdsfortegnelse Opret engelsk version af hjemmesiden... 2 Indledning:... 2 Metode 1 en samling af sider, med kun en engelsk version:... 3 Metode 2 Eksisterende sider med både en dansk og en engelsk

Læs mere

Elevadministrations modulet. Brugervejledning Optagelse.dk

Elevadministrations modulet. Brugervejledning Optagelse.dk Elevadministrations modulet Brugervejledning Optagelse.dk Elevadministrations modulet Brugervejledning Optagelse.dk Forfatter: Tine Kanne Sørensen UNI C UNI C, 19.12.2013 Indhold 1 Indledning... 5 1.1

Læs mere

Fremsøg sendte og modtagne meddelelser

Fremsøg sendte og modtagne meddelelser Fremsøg sendte og modtagne meddelelser Denne vejledning beskriver, hvordan man som myndighed, kan fremsøge sendte og modtagne meddelelser i Digital Post Administrationsportalen, samt hvilke forudsætninger

Læs mere

Advanced Word Template Brugermanual

Advanced Word Template Brugermanual Advanced Word Template Brugermanual Forord: Advanced Word Template er et værktøj, der anvendes sammen med Microsoft Word til at opbygge ensartet beskrivelser på en mere intelligent måde end Copy and Paste

Læs mere

SKOLELOGIN KNANPU1 FULDE NAVN ANAN PUSKAR EMAIL [email protected] URL TIL LØSNING HTTP://WWW.ANANP.DK/SURVEY URL TIL PORTFOLIO

SKOLELOGIN KNANPU1 FULDE NAVN ANAN PUSKAR EMAIL ANAN-1991@HOTMAIL.COM URL TIL LØSNING HTTP://WWW.ANANP.DK/SURVEY URL TIL PORTFOLIO SKOLELOGIN KNANPU1 FULDE NAVN ANAN PUSKAR EMAIL [email protected] URL TIL LØSNING HTTP://WWW.ANANP.DK/SURVEY URL TIL PORTFOLIO HTTP://WWW.ANANP.DK/PORTFOLIO Opgavebeskrivelse Jeg er ansat hos firmaet

Læs mere

Kom i gang med SAS STPbaserede

Kom i gang med SAS STPbaserede make connections share ideas be inspired Kom i gang med SAS STPbaserede webapplikationer Lars L. Andersson Chefkonsulent Webapplikationer Interaktion med serverbaserede data via skærmbilleder leveret gennem

Læs mere

Conventus og SFGIF Hvordan opretter jeg en ny træner?

Conventus og SFGIF Hvordan opretter jeg en ny træner? Kaj Heydt 18-09- INDHOLDSFORTEGNELSE LOG IND I CONVENTUS... 3 TRÆNEREN ER OPRETTET I CONVENTUS MEN HAR INGEN RETTIGHEDER... 4 TRÆNEREN ER IKKE OPRETTET I CONVENTUS... 10 TRÆNEREN KNYTTES / FJERNES FRA

Læs mere

3. SEMESTER 2. PROJECT MULB Gruppe 1. 20. september 2015

3. SEMESTER 2. PROJECT MULB Gruppe 1. 20. september 2015 PROJECT DATABASE 3. SEMESTER 2. PROJECT MULB Gruppe 1. 20. september 2015 Ved at underskrive dette dokument bekræfter vi, at det indsendte materiale alt sammen er vores eget materiale og arbejde. Andreas

Læs mere

Brugervejledning til anmelder

Brugervejledning til anmelder Version 0.8 ERHVERVSSTYRELSEN ANMELDELSE AF TJENESTEYDELSER I RUT Indholdsfortegnelse 1 INDLEDNING...3 2 ADGANG TIL RUT...3 2.1 Login...4 2.1.1 Login med brugernavn og password...5 2.1.2 Oprettelse af

Læs mere

Mbridge tilmeldingssystem Version Vejledning.

Mbridge tilmeldingssystem Version Vejledning. Mbridge tilmeldingssystem Version 23-03-2018. Vejledning. Indholdsfortegnelse. Indledning...2 Tilmelding til turnering (spillere)...2 Slet tilmelding...4 Opsætning af turneringer (turneringsleder)...5

Læs mere

Vejledning til. LearnSpace

Vejledning til. LearnSpace Vejledning til LearnSpace Version 13. 08. 2015 Indholdsfortegnelse Om LearnSpace... 2 Oprette et nyt kursus i egen afdeling... 3 Aktivere selvtilmelding til et kursus... 5 Tilmelde undervisere der må redigere

Læs mere

Rationel VinduesDesigner TM Brugervejledning

Rationel VinduesDesigner TM Brugervejledning Rationel VinduesDesigner TM Brugervejledning indhold: introduktion Side 2 Funktionsliste Side 3 Få adgang til systemet Side 4 opload dine billeder Side 5 Sådan bruges systemet Side 6 Gem dine eksempler

Læs mere

HTML, PHP, SQL, webserver, hvad er hvad??

HTML, PHP, SQL, webserver, hvad er hvad?? Dagens menu HTML og PHP: Baglæs fra output til input PHP: Variable, strenge og arrays Funktioner, oprettelse og kald (og variable på tværs af funktioner) echo vs return? if-else konstruktioner MySQL: Hvad

Læs mere

Database design for begyndere

Database design for begyndere Denne guide er oprindeligt udgivet på Eksperten.dk Database design for begyndere Denne artikel beskriver hvordan man kommer fra ide til database design. Den stopper inden normal former. Den forudsætter

Læs mere

Brugervejledning til udfyldelse og udstedelse af Europass Mobilitetsbevis i Europass Mobilitetsdatabasen

Brugervejledning til udfyldelse og udstedelse af Europass Mobilitetsbevis i Europass Mobilitetsdatabasen Brugervejledning til udfyldelse og udstedelse af Europass Mobilitetsbevis i Europass Mobilitetsdatabasen Europass Mobilitetsbevis skal udfyldes og udstedes i mobilitetsdatabasen: http://mobilitet.europass.dk/.

Læs mere