PHP- og MySQL-innføring
|
|
|
- Halvard Ellingsen
- 9 år siden
- Visninger:
Transkript
1 PHP- og MySQL-innføring En innføring i PHP og MySQL fra Hardware.no. Vegard Andreas Larsen André Kristoffer Dahl
2 2 Om forfatterne Vegard Andreas Larsen er programvareansvarlig for Hardware.no, og har drevet med PHP siden Han er en Zend Certified PHP Engineer, og studerer datateknikk ved NTNU, retning dataog informasjonsforvaltning. På fritiden driver han e-posttjenesten spamavert.com. Hans personlige nettside finnes på vega.rd.no. Vegard har skrevet kapittel 4 og utover, og har satt sammen og redigert denne boken. Du kan nå Vegard via e-post til [email protected]. André Kristoffer Dahl er journalist for Hardware.no, og har skrevet de første 3 kapitlene i denne serien. Du kan nå André Kristoffer via e-post til [email protected]. Om e-boken Denne e-boken er utgitt av Hardware.no, og er en redigert samling av artiklene i vår innføring i PHP og MySQL. Kapitlene har blitt noe redigert i forhold til artikkelserien som ble publisert på Hardware.no. E-boken blir oppdatert etterhvert som det kommer nye kapitler i vår introduksjonsserie. Boken er tilgjengelig for gratis nedlasting fra Hardware.no, og skal ikke legges for nedlasting andre steder enn dette. Om du har funnet boken en annen plass kan du rapportere det til [email protected]. Feil og mangler i boken kan rapporteres til samme adresse.
3 3 Innholdsliste Kapittel 1. Det grunnleggende... 6 Historien til PHP... 6 Hva er egentlig PHP?... 8 Alt foregår på serveren... 8 Så hva trenger man PHP til?... 9 Klientbaserte teknologier... 9 Installasjon av PHP... 9 Hello World! Fra HTML til PHP og tilbake Inkludering av filer Flere inkluderingsfunksjoner Så hvilken av de skal jeg bruke? Oppsummering Kapittel 2. Syntaks, variabler og ut-data PHP er tilgivende PHP er som C Start- og sluttagg PHP bryr seg ikke om mellomrom (whitespace) Semikolon Kommentarer Variabler - mellomlagre av informasjon Variabler er følsomme for store og små bokstaver Endre verdien til variabler Forskjellige typer variabler De forskjellige variabeltypene Apostrof eller anførselstegn? echo print Sammendrag Kapittel 3. Kontrollering av verdier if-else og boolske konstanter Sammenlikne verdier Logiske operatorer Else if Sammenlikne verdier som ikke er heltall Switch Switch med strenger Løkker - while do-while Mer om løkker - for La oss bruke det i praksis! break og continue Uendelige løkker... 33
4 4 Alternativ kontroll-syntaks Oppsummering Kapittel 4. Lister Opprette arrays Løkker og arrays Mer om indekser Sortering Vanlige operasjoner Køer og stakker Oppsummering Kapittel 5. Funksjoner Hva er en funksjon? Vanlige feller Returnere verdier Returnere flere verdier Oppsummering Kapittel 6. Ta imot data fra brukeren Basiskunnskaper Sikkerhet Regulære uttrykk Feilmeldinger Ta imot arrays POST, GET og REQUEST Ta imot filer Oppsummering Kapittel 7. Objekt-orientering Forord Klasser og objekter Lage objekter Arv Synlighet Statiske metoder og variable Objekt-operasjoner Oppsummering Kapittel 8. Databaser og MySQL Tilgang til MySQL Datatyper Tabeller Uthenting av data Mer uthenting Oppdatering Sletting Oppsummering Kapittel 9. Databasenormalisering... 81
5 Dagens eksempel Første normalform Andre normalform Tredje normalform Løsning Oppsummering
6 6 Kapittel 1. Det grunnleggende Kapittel 1. Det grunnleggende Vi starter opp med en stor artikkelserie som gir deg en innføring i bruk av PHP og MySQL. Kapittel 1 gir deg en introduksjon til det helt elementære. Er du en av mange som har lekt litt med HTML, men savner mer funksjonalitet? I denne artikkelserien vil vi lære deg å bruke PHP og MySQL til å lage dynamiske webløsninger, slik at du kan ta webutviklingen til et nytt nivå. For å få best mulig utbytte av denne innføringen er det en fordel at du kan HTML og har en viss kjennskap til programmering. Dette er imidlertid ikke et krav - du skal kunne skjønne det meste uten noen som helst bakgrunnskunnskap. I dette første kapittelet vil vi se på hva PHP egentlig er og hvorfor man skal bruke det. Videre vil du lære å sette opp PHP på din egen maskin, og du vil også lære elementær koding. Planen er at denne artikkelserien skal gå over rundt ti kapitler. Først vil du lære deg PHP, og etterhvert vil vi gå over til å vise hvordan PHP kan brukes sammen med databaseverktøy som MySQL. Så vil vi bruke denne kunnskapen i praksis. Så, la oss starte! Historien til PHP Før vi begynner å bruke PHP i praksis kan det være lurt å vite hva det er vi egentlig driver med. La oss ta en titt på hvordan PHP startet og hvordan det har utviklet seg med tiden. Historien til PHP går så langt tilbake som til Dansk-kanadieren Rasmus Lerdorf 1, programvareutvikler og medlem av utviklingsteamet til Apache, ønsket å holde oversikt over besøkende til hans personlige nettside. 1 Hjemmeside på
7 Kapittel 1. Det grunnleggende 7 Til dette utviklet han en skriptsamling basert på Perl og CGI. Mange fikk øynene opp for Lerdorfs arbeid, og etter stor etterspørsel lanserte han Personal Home Page Tools (a.k.a. the PHP Construction Kit) 8. juni Kort tid senere ble versjon 2 lansert, da under navnet PHP/FI. Denne inkluderte Form Interpreter, et verktøy som gjorde det mulig å sende spørringer til en SQL-database. Det var nå moroa virkelig startet. I midten av 1997 brukte rundt nettsteder PHP. Nå som prosjektet ble så stort var det umulig for én mann å håndtere det alene. Nå står en liten gruppe utviklere for utviklingen av PHP, med hjelp fra bidragsytere over hele verden. To nøkkelpersoner i utviklingen er de to israelske programmererne Zeev Suraski og Andi Gutmans. I 1997 skrev de Rasmus Lerdorf om hele parseren til PHP, og i oktober 1997 ble PHP/FI 2 lansert. Samtidig ble navnet byttet til Hypertext Preprocessor, som er navnet den dag i dag. I juni 1998 ble PHP 3 lansert offentlig. Eksplosiv økning Fra og med fjerde kvartal av 1998 opplevde PHP en eksplosiv økning, da prosjekter basert på åpen kildekode for alvor kom frem i lyset. Rundt nettsteder brukte PHP på en eller annen måte i oktober Året senere var tallet på én million. PHPs vekstkurve I mai 2000 ble versjon 4 lansert, da med den nye Zend Engine. I dag er PHP installert på ca. 20 millioner nettsider verden over. PHP 5 ble lansert 13. juli 2004, og er ved siden av PHP 4.4 de versjonene som har offisiell støtte i dag. PHP 5 forsøker å tilby noe mange brukere har etterspurt opp gjennom årene - mulighet for objektorientert programmering (OOP). Selv om OOP-støtten per dags dato er langt fra optimal, bringer den PHP mer på linje med objektorienterte programmeringsspråk som Java og C++. Du vil lære mer om objektorientert programmering i PHP i et senere kapittel.
8 8 Kapittel 1. Det grunnleggende Hva er egentlig PHP? For dere som ikke har kjennskap til PHP fra før av kan hele opplegget virke litt merkelig. La meg forklare hva PHP egentlig går ut på, og hvorfor vi bruker det. PHP er et skriptespråk på serversiden som kan brukes til å generere blant annet HTML. Andre liknende skriptespråk er blant annet Microsofts Active Server Pages (ASP), Macromedias ColdFusion og Suns Java Server Pages (JSP). PHP er blant de få språkene som er skrevet med åpen kildekode. Dette vil si at hele kildekoden er tilgjengelig gjennom PHP.net 2. Enkelte kaller PHP for "ASP med åpen kildekode" fordi funksjonaliteten er liknende ASP. Formuleringen er imidlertid misledende, ettersom PHP ble utviklet før ASP (første versjon av ASP kom i 1996). Den største fordelen med PHP i forhold til andre liknende teknologier er det at det er så og si helt plattformuavhengig. Du kan kjøre PHP på systemer basert på Unix, Windows og Mac OS X. Alt foregår på serveren PHP er ikke ment til å definere utseendet til en nettside og bestemmer i utgangspunktet heller ikke innholdet. Til slike oppgaver har man klientbaserte teknologier som Cascading Style Sheet (CSS) og Hyper-Text Markup Language (HTML). Hva PHP gjør er i de fleste tilfeller helt usynlig for brukeren. En bruker vil ikke nødvendigvis kunne skille et HTML-dokument som er servert av PHP fra et vanlig HTML-dokument. Dette fordi resultatet av PHP normalt er HTML. PHP genererer HTML-kode som blir levert til en bruker 2
9 Kapittel 1. Det grunnleggende 9 På bildet ovenfor ser vi en HTML-side som blir levert til nettleseren til en bruker. Her ser vi det eksakt samme dokumentet som er levert av et PHP-skript. Som vi ser merker ikke brukeren noen som helst forskjell, for forskjellen ligger på serversiden. Så hva trenger man PHP til? De av dere som har laget nettsider i HTML har sannsynligvis lagt merke til en vesentlig negativ ting. La oss si at du har en stor nettside basert på en rekke HTML-dokumenter. På denne nettsiden har du en meny. Men så finner du ut at du vil endre noe på menyen. Hva i all verden skal du gjøre nå? Den eneste muligheten er å endre hver enkelt HTML-fil. Det er her PHP kommer inn i bildet - med PHP kan du ha en enkelt fil som inneholder kodingen til menyen, og deretter bruke en svært enkel funksjon for å legge menyen inn på hver enkelt side. HTML er altså et statisk språk, mens PHP på sin side er dynamisk. Riktignok finnes det teknologier som gjør en liknende løsning mulig via HTML, slik som frames. Dette er imidlertid ikke en god metode, da det er ansett som en utdatert teknologi. I tillegg til at PHP gjør det svært enkelt å lage statiske websider byr språket på en rekke funksjoner du aldri kunne ha klart å gjøre mulig med bare HTML (du vil oppdage dette etterhvert som du leser flere kapitler av denne innføringen). Har du for eksempel tenkt på hvordan forumet vårt og publiseringssystemet er laget? Jepp, du gjettet riktig. Det er alt basert på PHP. Hadde det ikke vært for PHP og liknende teknologier ville verdensveven fortsatt vært i steinalderstadiet. Klientbaserte teknologier Det finnes i dag en rekke klientbaserte teknologier som muliggjør diverse funksjoner. Jeg kan nevne Javascript, Java applets, Flash og VBscript. Problemet med samtlige av disse teknologiene er imidlertid at de avhenger helt og holdent på brukeren, ikke på serveren som leverer informasjonen. For eksempel kan brukere ha deaktivert JavaScript av sikkerhetshensyn, eller nettleseren kan ha ikke-eksisterende eller utilstrekkelig støtte for Java eller Flash. Disse problemene unngår man med serverbaserte-teknologier som PHP, for all behandling av kode skjer på serveren. Installasjon av PHP Den vanligste bruken er å leie serverplass med støtte for PHP. For vanlig testing kan det imidlertid være like greit å sette det opp på egen maskin. La oss se hvordan det gjøres. Vi har tatt utgangspunkt i bruk av Apache 2.2 som webserver, PHP og MySQL Installasjon på Unix Erfarne PHP-utviklere vil ofte si at Unix-baserte systemer er det beste å bruke for PHP. Det er også derfor svært mange leverandører av serverplass benytter dette operativsystemet. For å sette opp PHP trenger du å ha installert en webserver. Vi tar utgangspunktet i Apache 2.0, som er nyeste versjon av den mest utbredte varianten. Faktisk leveres mange Linux-distrubisjoner med LAMP (Linux Apache MySQL PHP), og i mange tilfeller trenger man derfor ikke å installere noe som helst. Det er imidlertid en stor sjanse for at både Apache- og PHP-versjonen du har installert er utdatert. Brukere av Debian eller Ubuntu kan installere Apache og PHP svært enkelt (takk til Tor Henning Ueland for denne). Alt som trengs å gjøres er å skrive:
10 10 Kapittel 1. Det grunnleggende sudo apt-get install apache2 sudo apt-get install php5 Har du ikke Debian eller Ubuntu må du imidlertid gå for en mer avansert løsning. Det første du må gjøre er å laste ned Apache 3. Deretter må du "unzippe" og "untare" Apache-distrubisjonen: gzip -d httpd-2_0_nn.tar.gz tar xvf httpd-2_0_nn.tar Nå skal Apache-serveren bygges. Du kan selvsagt selv velge hvor den skal bli plassert - vi har tatt utgangspunkt i /usr/local/machine. --enable-so vil la Apache laste inn PHP-støtte og en rekke andre nyttige elementer. cd httpd-2_0_nn./configure --prefix=/usr/local/apache2 --enable-so make make install For å sjekke at Apache-serveren fungerer starter du den på den vanlige måten, altså slik: /usr/local/apache2/bin/apachectl start Deretter avslutter du Apache igjen. /usr/local/apache2/bin/apachectl stop Nå kan gå videre til konfigureringen av PHP. cd../php-nn Nå konfigurerer vi PHP med forskjellige valg. Det du burde gjøre er konfigurere for Apache 2 og MySQL-støtte. Vær obs på at adressen til apxs kan variere fra system til system, den kan like gjerne være kalt apxs2../configure --with-apxs2=/usr/local/apache2/bin/apxs --with-mysql make make install Nå er det tid for å installere php.ini-filen. Denne filen gir deg mulighet for å endre det meste av instillinger i PHP. Mer om dette kan du lese i et senere kapittel. cp php.ini-dist /usr/local/lib/php.ini Nå er tiden inne for å endre httpd.conf-filen til å laste PHP-modulen. LoadModule php5_module modules/libphp5.so Helt til slutt skal vi gi beskjed til Apache om hvilke filer som skal leses som PHP. I vårt eksempel har vi valgt PHP- og HTML-filer, noe som vil si at alle filer som enten har filendelsen.php eller.html vil bli lest som PHP-filer. AddType application/x-httpd-php.php AddType application/x-httpd-php.html Nå er det bare å starte Apache på nytt, og alt skal fungere. Husk på at hver gang du endrer HTTPkonfigurasjonen eller php.ini-filen må serveren restartes. 3
11 Kapittel 1. Det grunnleggende 11 /usr/local/apache2/bin/apachectl start Installasjon av PHP på Windows NT/2000/XP Mange ønsker sikkert å benytte seg av Windows når de skal teste PHP-koding. Installasjonen er langt lettere på Windows, ettersom den tar utgangspunkt i allerede kompilert kode. Det finnes i dag en rekke pakker som gjør det mulig å installere Apache, PHP og MySQL svært enkelt. Av disse er nok XAMPP 4 den beste, da den i skrivende stund støtter nyeste versjon av Apache (2.2.2), PHP (5.1.4) og MySQL (5.0.21). Svar "ja" til alle spørsmål du får under installasjonen. Et stort Vi bruker XAMPP når vi installerer på Windows problem med XAMPP er at programmet må konfigureres skikkelig for å unngå store sikkerhetshull. Etter installasjonen åpner du og følg deretter instruksjonene for konfigurasjon. For å sjekke at installasjonen av XAMPP var vellykket, gjør følgende: Åpne et nytt dokument i teksteditoren din, og skriv: phpinfo(); Denne filen lagrer du som info.php, og legger den i xampp/htdocs. Deretter starter du en nettleser og åpner localhost/info.php eller /info.php. Har du gjort alt riktig skal du nå få opp masse info om PHP-konfigurasjonen din. Installer selv (Windows) Hvis du imidlertid ønsker å gjøre ting selv, for å ha full kontroll over hva du gjør og hvor du legger ting, så følg innføringen under. Last ned og installer Apache Win32 Binary fra Apache.org 5. Selve installasjonen skal være nokså selvforklarende. Deretter laster du ned PHP fra PHP.net 6. Her burde du velge zip-pakken, ettersom varianten som bruker et installeringsprogram kun virker med Internet Information Services (IIS), som følger med Windows Server Nå pakker du ut zip-filen til stedet du ønsker; C:\PHP er det vanligste. Velg samtlige filer som har filendelsen.dll, og kopier de til C:\Windows\System32. Egentlig trenger du ikke alle filene, men for enkelhetens skyld er det like greit å ta alle sammen. Kopier php.ini-recommended til C:\Windows, og endre navnet på den til php.ini. Deretter åpner du denne filen i en teksteditor, for eksempel Notisblokk (Start > Kjør > notepad). Naviger deg frem til doc_root (Ctrl + B for å søke i Notisblokk). Denne skal bli satt til mappen du har
12 12 Kapittel 1. Det grunnleggende dokumentene til Apache i, for eksempel C:\Programfiler\Apache Software Foundation\Apache2.2\htdocs. Nå går du tilbake til Apache-mappen, og finner mappen kalt conf. Her åpner du httpd.conf med en teksteditor, og sett DocumentRoot (skal finnes to steder) til mappen du skrev inn ovenfor (for eksempel C:/Programfiler/Apache Software Foundation/Apache2.2/htdocs). Finn ServerAdmin (fortsatt i httpd.conf), og sett denne til e-postadressen din. Så finner du ServerName, og setter denne til Deretter føyer du til følgende nederst i dokumentet: AddModule mod_php5.c LoadModule php5_module modules/php5apache2.dll AddType application/x-httpd-php.php.html Åpne et nytt dokument i teksteditoren din, og skriv: phpinfo(); Denne filen lagrer du som info.php, og legger den i mappen for dokumenter, som ved de forrige stegene. Deretter starter du en nettleser og åpner eller /info.php. Har du gjort alt riktig skal du nå få opp masse info om PHPkonfigurasjonen din. Det er imidlertid ikke få ganger ting ikke fungerer som det skal første gang. Fremgangsmåten varierer fra versjon til versjon og fra operativsystem til operativsystem. Fungerer det ikke slik du hadde håpet kan du ta en titt i PHPs 7 eller Apaches 8 dokumentasjon på nettet. Eventuelt kan du benytte metoden med XAMPP (se toppen). Installasjon på Mac OS X Så har tiden kommet for Mac OS X. Det er ikke mange år siden prosjekter med åpen kildekode, slik som PHP, begynte å støtte Macintosh-plattformen. Mange ser på OS X som det beste av to verdener - enkelheten til Windows men samtidig gode muligheter for tekstbaserte kommandoer. Operativsystemet ditt kom sannsynligvis med både Apache og PHP installert på forhånd. Det er imidlertid mulig at dette er eldre versjoner, og det er derfor lurt å laste ned nyeste versjon. Problemet er bare at å laste ned kildekoden og kompilere den selv er langt fra lett for uerfarne brukere. Du kan imidlertid få en del tips i PHP-manualen 9. Det finnes imidlertid en rekke uoffisielle sider som tilbyr nyeste versjon av PHP ferdig kompilert for OS X. Vi kan anbefale Entropy 10. Installasjonen der skal være lett, det er bare å følge instruksjonene. Hvis du har PHP 5 og Apache 2 gjennom operativsystemet ditt, så følg disse stegene for installasjon: Åpne Apaches konfigureringsfil med administratorrettigheter
13 Kapittel 1. Det grunnleggende 13 sudo open -a TextEdit /etc/httpd/httpd.conf Rediger filen, og fjern kommentartegnet (;) fra følgende linjer: Load Module php5_module AddModule mod_php5.c AddType application/x-httpd-php.php Restart serveren. sudo apachectl graceful Nå kan vi sjekke om alt fungerer som det skal. Åpne en teksteditor og skriv følgende: phpinfo(); Denne filen lagrer du som info.php, og legger den i mappen til siden din. Deretter starter du en nettleser og åpner eller /~brukernavn/info.php. Har du gjort alt riktig skal du nå få opp masse info om PHPkonfigurasjonen din. Hello World! Nå som vi har fått PHP til å fungere er det endelig tid for litt koding. Hva er vel da bedre enn den oppbrukte "hello world" som vi alle er så grundig lei av? Det første du må gjøre er selvsagt å åpne en teksteditor. For Windows kan Notisblokk fungere flott, men et skikkelig program som Zend Studio 11 er langt bedre og mer oversiktlig. Minuset er at det koster penger. Et annet alternativ er PHPEclipse 12. Bortsett fra en kronglete installasjon er dette et godt program. Når vi nå har en teksteditor åpen skriver du følgende: echo("hello, evil world!"); PHP starter alltid med, og avsluttes med. All tekst innenfor vil oppfattes som PHP-kode, og vil bli behandlet deretter. Echo()-funksjonen skriver teksten som står innenfor (" og "), og avsluttes (som alle andre funksjoner i PHP) med et semikolon. Lagre filen som hello.php i mappen for filene på serveren. Hvor denne mappen er lokalisert avhenger av hvilket operativsystem du har og hva du selv har valgt (se side 5-7). Når du nå åpner localhost/hello.php skal du se teksten "Hello, evil world!". Gratulerer, du har laget ditt første PHP-skript! Fra HTML til PHP og tilbake En spennende ting med PHP er den tette integrasjonen med HTML. Dette gjør det lett å gå frem og tilbake fra PHP-kode i et dokument. Se det følgende eksempelet:
14 14 Kapittel 1. Det grunnleggende <html> <head> <title> echo("dette er en tittel som er laget ved hjelp av PHP");</title> </head> <body> <p> Dette avsnittet har egentlig ingen funksjon, det er her bare for å vise at du når som helst echo("kan gå over til PHP-kode uten noen som helst problemer (ser du? Kult, eh?)"); </p> </body> </html> Hvis du lagrer denne filen som et PHP-dokument og åpner den i en nettleser vil du se at tittel og tekst fungerer helt flott. Hvis du viser kildekoden til dokumentet vil du også se at det ikke er noen spor av PHP-kode der, alt du ser er HTML-kode. Dette er fordi all PHP-kode blir kjørt på serveren, mens HTML blir tolket hos klienten (leseren). Inkludering av filer Husker du at jeg tidligere snakket om problemet med at HTML er statisk? Det er på tide å vise hvorfor PHP er løsningen på alle slike sorger. La oss fortsatt bruke eksempelet med at vi skal redigere et element på menyen. Vi ser for oss at menyen blir definert slik i HTML: <ul id="meny"> <li><a href="index.php">hovedsiden</a></li> <li><a href="bilder.php">bilder</a></li> <li><a href="forum.php">forum</a></li> </ul> Med PHP kan vi bruke funksjonen include(). Denne inkluderer en valgt fil på det valgte området, og utfører eventuelle kommandoer filen inneholder. include('meny/hovedmeny.php'); Denne kan du lagre som for eksempel index.php. Teksten som står innenfor (' og ') definerer hvilken fil som skal inkluderes. Som alle funksjoner i PHP markerer et semikolon at funksjonen er ferdig. Vi ser for oss at vi har følgende i meny/hovedmeny.php: <ul id="meny"> <li><a href="index.php">hovedsiden</a></li> <li><a href="bilder.php">bilder</a></li> <li><a href="forum.php">forum</a></li> </ul> Nå vil innholdet i hovedmeny.php bli vist hver gang en forespørsel om å vise menyen blir sendt. Skal vi nå gjøre en endring på menyen er det bare å endre hovedmeny.php. Smart, sant? Flere inkluderingsfunksjoner Det finnes totalt fire funksjoner som inkluderer filer. Det er bygd opp av to sett med funksjoner - include-funksjonene og require-funksjonene. I tidligere versjoner av PHP var forskjellen i
15 Kapittel 1. Det grunnleggende 15 funksjonaliteten og hastigheten store mellom disse to settene, men dette stemmer ikke i dag. Den eneste forskjellen er i dag hva slags feilmelding de returnerer hvis noe går galt. include() og include_once() vil normalt generere en feilmelding ved en feil, mens require() og require_once() vil generere en feilmelding av typen "fatal error" og stoppe hele skriptet. Som man ser av navnene til funksjonene, include_once() og require_once() er forskjellig fra include() og require() ved at de bare lar en fil bli inkludert én eneste gang i løpet av hele PHP-skriptet som kjøres. Dette kan være svært nyttig i mange tilfeller, blant annet hvis du inkluderer filer som inneholder PHP-funskjoner. Dette fordi å redeklarere funksjoner vil resultere i en fatal feilmelding og hele skriptet vil bli avbrutt. I tillegg er det ikke uvanlig å ha (i større systemer) filer som inkluderer filer som inkluderer filer som igjen inkluderer filer, og det kan i mange tilfeller være vanskelig å huske om du har inkludert en funksjon tidligere. Dermed er *_once()-funksjonene svært nyttige. Så hvilken av de skal jeg bruke? Ved små skript er det lettest å bruke include(), og det er også funksjonen jeg vil benytte når jeg skriver eksempler i denne innføringen. Generelt sett kommer det mye an på hvordan du koder - hvis du vil holde deg selv i øret og ikke la det fungere hvis du har skrevet noe feil bruker du require(). I den andre enden av skalen finner vi include_once(), som vil gjemme alle konsekvenser av dine dårlige kodevaner. Så er første kapittel av denne innføringen snart over. Jeg håper at du har hatt utbytte av det du har lest, og at du har likt det du har lest like mye som jeg har likt å skrive det. Husk at jeg som alltid er åpen for tilbakemeldinger. Oppsummering PHP er et skriptespråk som kjøres på serversiden, og sender informasjonen i form av HTMLdokumenter til klienten (leseren). PHP har siden lanseringen i 1995 opplevd en eksplosiv vekst, og er i dag i bruk av nærmere 20 millioner nettsteder. PHP gjør det lett å lage dynamiske webløsninger, og brukes aktivt på svært mange store nettportaler verden over. Vårt eget forum og publiseringssystem baserer seg på PHP. PHP-kode markeres med og, og alt innenfor vil bli tolket som PHP-kode. Alle funksjoner skal i PHP avsluttes med et semikolon. Videre printes tekst og HTML-koder ut med funksjonen echo(), og filer blir inkludert med include()- og require()-funksjonene. I neste kapittel vil vi gå løs på syntaksen til PHP, lære om variabler og mer om hvordan ut-data sendes fra PHP. Planen er at kapittel to vil komme om rundt én uke.
16 16 Kapittel 2. Syntaks, variabler og ut-data Kapittel 2. Syntaks, variabler og ut-data Er du en av mange som har lekt litt med HTML, men savner mer funksjonalitet? I denne artikkelserien vil vi lære deg å bruke PHP og MySQL til å lage dynamiske webløsninger, slik at du kan ta webutviklingen til et nytt nivå. For å få best mulig utbytte av denne innføringen er det en fordel at du kan HTML og har en viss kjennskap til programmering. Dette er imidlertid ikke et krav - du skal kunne skjønne det meste uten noen som helst bakgrunnskunnskap. I kapittel 1 av denne guiden så vi på hva PHP er, historien til PHP og hvordan PHP installeres. Til slutt så vi på litt enkel programmering som "hello world" og inkludering av filer. Nå i kapittel 2 vil vi se nærmere på syntaksen til PHP, altså hvordan PHP-kode skrives. Videre vil vi se grundig på variabler, og til slutt se litt på hvordan man sender ut-data fra PHP. Ettersom det er vanskelig å forklare syntaksen til PHP uten å komme med spesifikke eksempler vil forklaringen av syntaksen og forklaringen av variabler gå litt på kryss og tvers av hverandre. Dette vil også fortsette i de neste kapitlene, hvor vi vil se på tall, matematiske operasjoner, kontroll, funksjoner og mye mer. Har du ikke lest kapittel 1 vil jeg anbefale deg å gjøre det før du fortsetter å lese dette kapittelet. PHP er tilgivende Det viktigste å vite om PHP er at språket forsøker å være så tilgivende som mulig. Programmeringsspråk varierer mye i hvor strengt de krever at syntaksen blir overholdt. Hvis du for eksempel skal skrive et program som styrer et kjernekraftverk hadde det vært utrolig kjedelig hvis du hadde gjort en feil i kodingen uten at noen feilmelding kom opp. PHP er imidlertid ikke, tro det eller ei, designet for å styre kjernekraftverk. Siden PHP startet opp som en skriptsamling som enkelt skulle kunne enkelt installeres på personlige nettsider er filosofien den dag i dag at programmereren skal gi et minimum at informasjon, og PHP-parseren skal selv forsøke å finne ut resten. PHP kan imidlertid ikke lese tankene dine, og vil gi beskjed hvis syntaksereglene er så grovt brutt at PHP ikke forstår hva du har tenkt at skal gjøres. Når du ser ordene parse error indikerer det at du har en feil i syntaksen din, og at PHP-parseren gir beskjed om dette. PHP er som C PHP sin syntaks har lånt mange elementer fra programmeringsspråket C. Er du en av de heldige som har programmert i C før har du en stor fordel, for PHP er ikke så ulikt C. Lurer du på hvordan noe skrives i PHP, så forsøk å skrive det slik du ville skrevet det i C. Start- og sluttagg PHP starter alltid med taggen, og slutter med. Alt innenfor vil bli tolket som PHP-kode, og behandlet deretter av PHP-parseren. Man kan også starte PHP-skript med <?, forutsatt at short_open_tag i php.ini er satt til on. Dette kan imidlertid by på problemer, ettersom XML-filer starter på akkurat samme måte. Jeg vil derfor anbefale å bruke.
17 Kapittel 2. Syntaks, variabler og ut-data 17 PHP bryr seg ikke om mellomrom (whitespace) Ok, overskriften er en smule misvisende. I PHP kan det være viktig å putte inn mellomrom, men når det først er gjort spiller det ingen rolle hvor mange mellomrom du skriver. Det samme gjelder tabs og linjeskift. Se dette eksempelet: $variabel = 2 + 2; $variabel = ; $variabel = 2 + 2; Hvert av de tre eksemplene over vil fungere helt fint. Med andre ord vil ett mellomrom oppfattes som det samme som uendelig mange mellomrom. Semikolon I PHP er et utsagn (statement) et uttrykk (expression) som er avsluttet med et semikolon (;). Vi kan si at et uttrykk er som en frase, mens et utsagn er som en hel setning. Semikolonet indikerer at utsagnet er ferdig. Hvis du ikke skjønner dette nå - ikke fortvil. Du vil selv kunne se dette i praksis senere i kapittelet og i andre kapitler. Kommentarer Når man skriver store skript kan det være svært nyttig å kommentere kodingen man gjør. Uten kommentering blir koden fort uoversiktlig, og det kan være vanskelig å skjønne hva den som har skrevet koden har tenkt. Alle kommentarer vil bli hoppet over av PHP-parseren, og er der kun for at du eller en annen ved en senere anledning kan lese det. Med andre ord vil alt som er markert som kommentarer PHP bruker samme metode for kommentarer over flere linjer som C - den starter med /*, og ender med */ /* Dette er en kommentar som går over mange linjer. Det siste ordet vil gi en feil, ettersom det står */ utenfor I tilfellet over vil utenfor bli tolket som PHP-kode, ettersom det ikke står innenfor kommentartegnene. Vi har også alternativer for kommentarer som kun går over én linje. Her har vi C++- og Javavarianten // og Perl-varianten #. # Dette er en kommentar # Og enda en linje med kommentar // Dette er også en kommentar. // Begge disse typene støtter kun en linje med tekst, // så det siste ordet her vil gi en feil Den observante leser vil se at dette ikke stemmer med det jeg sa tidligere om at PHP ikke er sensitiv for mellomrom, tabs og linjeskift (whitespace). Kjære observante leser, du har helt rett. En mer riktig måte å si det på er at PHP ikke er sensitiv for såkalt "whitespace" etter at kommentarene er tatt ut fra koden.
18 18 Kapittel 2. Syntaks, variabler og ut-data Variabler - mellomlagre av informasjon Den vanligste måten å lagre informasjon i midten av et PHP-skript er å bruke variabler. En variabel har et navn og en verdi. For å kalle opp en variabel bruker vi navnet variabelen har, og tilbake får vi verdien den er lagret med. Med andre ord er variabler et mellomlager for informasjon. Se det følgende eksempelet: $testvariabel = "Dette er informasjonen som er lagret"; I PHP bruker vi alltid et dollartegn ($) for å indikere at vi snakker om en variabel. Ved å bruke et likhetstegn (=) gir vi variabelen en verdi. På venstre siden av likhetstegnet er variabelnavnet, mens det på høyresiden er verdien til variabelen. Skal vi nå skrive ut innholdet i variabelen gjør vi det slik: $testvariabel = "Dette er informasjonen som er lagret"; echo $testvariabel; Dermed vil informasjonen som variabelen ved navn testvariabel inneholder bli skrevet ut med echo-funksjonen. Variabler er følsomme for store og små bokstaver Generelt sett sier man at PHP ikke bryr seg om forskjellen på store og små bokstaver, noe som følger filosofien om at PHP skal være tilgivende. Det er imidlertid en ting som er viktig å merke seg; navn på variabler er følsomme for forskjell på store og små bokstaver. $variabel = 100; echo "Variabelen med navn variabel har verdien $variabel"; echo "Variabelen med navn VaRiaBeL har verdien $VaRiaBeL"; Ut-dataen du da vil se er: Variabelen med navn variabel har verdien 100 Variabelen med navn VaRiaBeL har verdien Variabelen med navn variabel er nemlig en helt annet variabel enn VaRiaBeL. Variabelen VaRiaBeL inneholder ikke noe informasjon, for den er ikke deklarert. Dette ser vi tydelig av utdataen. Endre verdien til variabler Hva hvis vi vil endre informasjonen som en variabel inneholder? Dette er selvsagt svært enkelt. Se det følgende eksempelet: $name = "André K. Dahl"; $name = "André Kristoffer Dahl"; echo "Forfatter: $name"; Her definerer vi først variabelen ved navn name til å inneholde teksten "André K. Dahl", for deretter å endre verdien til "André Kristoffer Dahl". Det er den sistnevnte verdien vi vil få hvis vi
19 Kapittel 2. Syntaks, variabler og ut-data 19 ber om å få verdien til variabelen. Det er i utgangspunktet ingen måte å finne ut at variabelen name har hatt en annen verdi før den endelige verdien. Se det følgende eksempelet: $car = "Volvo 850"; $old_car = $car; $car = "BMW 5-serie 520" echo "Min gamle bil var en $old_car. Min nye bil er en $car."; Ut-dataen fra dette skriptet ville vært "Min gamle bil var en Volvo 850. Min nye bil er en BMW 5- serie 520". Som du ser blir innholdet til old_car satt til det samme som innholdet i car, som er "Volvo 850". Grunnen til dette er at PHP leser fra toppen og nedover, slik at på det tidspunktet old_car ble definert var verdien av car "Volvo 850". Forskjellige typer variabler Det finnes en rekke typer variabler i PHP, som i alle programmeringsspråk. Disse typene spesifiserer hva slags verdier som kan bli lagret i de aktuelle variablene. Eksempelene til nå har kun tatt for seg strenger (strings), altså ren tekst. Til forskjell fra mange andre programmeringsspråk krever ikke PHP at vi spesifiserer typen til en variabel. Dette følger PHPs filosofi om at alt skal være så enkelt som mulig, og at språket skal være tilgivende. På tross av at vi ikke trenger å spesifisere hva slags type en variabel er har vi selvsagt mange forskjellige type variabler. PHP-parseren finner selv ut hva slags type en variabel er. I PHP finnes det totalt åtte typer variabler (det engelske navnet står i parantes): Heltall (integers) er hele nummer uten desimaler. For eksempel 145. Desimaltall (doubles) er tall med desimaler. For eksempel eller 65.0 (PS: Husk at du må bruke punktum, ikke komma). Boolske variabler (booleans) har kun to mulige verdier: TRUE eller FALSE. NULL er en type som kun har en verdi - NULL. Den brukes gjerne for å indikere at variabelen er tom. Strenger (strings) er flere tegn satt sammen. For eksempel "Vi benytter PHP 5.1.4". Arrays er navngitte og indekserte samlinger av andre verdier. Objekter (objects) er klasser som er definert av programmereren selv, som kan inneholde både andre typer verdier og funksjoner som er spesifikk til klassen. Ressurser (resources) er variabler som inneholder referanser til ressurser utenfor PHP. For eksempel en tilkobling til en database. På neste side vil vi se nærmere på de forskjellige typene. De forskjellige variabeltypene Som sagt trenger vi i PHP ikke å spesifisere hva slags informasjon en variabel skal inneholde. Om det er en streng, heltall eller desimaltall er opp til PHP-parseren å finne ut. Denne jobben gjør den svært godt, men i noen tilfeller kan det være nødvendig å hjelpe den litt på vei.
20 20 Kapittel 2. Syntaks, variabler og ut-data $pi = ; echo "Pi er omtrent $pi"; Her blir resultatet av regnestykket regnet ut, og lagret i variabelen pi. Hvis du kjører dette skriptet vil du dermed få teksten "Pi er omtrent ". Men hva hvis du vil at variabelen Pi skal lagre selve teksten " ", ikke selv regne det ut? $pi = " "; echo "Pi er omtrent $pi"; Alt som skulle til var å føye til noen hermetegn. Nå oppfatter PHP-parseren det som at variabelen pi inneholder en streng (string), og vil dermed ikke forsøke å regne det ut, men beholdet uttrykket. Ut-dataen hvis du kjører dette skriptet vil altså være "Pi er omtrent ". Apostrof eller anførselstegn? I PHP kan man i mange tilfeller selv velge om man vil benytte seg av apostrof (') eller anførselstegn ("). Mange sliter med å skjønne forskjellen, og blir overrasket når skriptene de skriver ikke fungerer som det er tenkt. En viktig faktor å huske på er at en apostrof godt kan puttes inn mellom anførselstegn, og omvendt. Se eksempelet: echo "I'm starting to understand this PHP-shit!"; Dette vil fungere helt fint. Apostrofen vil ikke oppfattes som et tegn på at echo-kommandoen er over, ettersom vi i eksempelet over bruker anførselstegn. Skriver vi derimot følgende: echo 'I can't understand this!';...vil vi få en feilmeldingen av typen parse error (unexpected T_STRING). Det er imidlertid svært stor forskjell på egenskapene til apostrof og anførselstegn. $variabel = "Dette er verdien"; echo '$variabel'; echo '<br>'; //Linjeskift i HTML echo "$variabel"; Kjører vi dette skriptet vil vi få følgende som ut-data: $variabel Dette er verdien Dette er fordi alt som står mellom apostrofer oppfattes som ren tekst. Har vi det mellom anførselstegn vil imidertid PHP-parseren oppfatte at det er en variabel, og vil skrive ut verdien av variabelen isteden.
21 Kapittel 2. Syntaks, variabler og ut-data 21 PHP har noen bestemte tegn som vil bli erstattet av andre karakterer hvis de starter med en skråstrek av typen \ (backslash). Disse fungerer kun ved bruk av anførselstegn ("), altså ikke ved bruk av apostrofer ('). \n blir erstattet med en ny linje. \r blir erstattet med et returkarakter. \t blir erstattet med en tab-karakter. \$ blir erstattet med et dollartegn. \" blir erstattet med et anførselstegn. \' blir erstattet med en apostrof. \\ blir erstattet med en skråstrek av den typen (backslash). Ønsker du dermed å skrive ut et dollartegn i samme echo-sekvens som du inkluderer en variabel, gjør du slik: Ut-dataen vi da vil få er "$dollar". Hadde vi derimot ikke brukt skråstreken hadde PHP-parseren lest det som en henvisning til variabelen med navn dollar. Hvis vi derimot setter inn disse tegnene ved bruk av apostrofer, så vil selve teksten bli skrevet ut (for eksempel \n). Det eneste unntaket er ved bruk av \', som naturlig nok vil skrive ut en apostrof. Prøv deg frem selv! echo Til nå har vi benyttet echo-funksjonen til å sende ut-data fra PHP. Denne funksjonen kan benyttes på følgende måter: og echo "\$dollar"; echo "Dette er en tekst."; echo("dette er en tekst."); Benytter du deg av den første metoden kan du gi flere argumenter, separert av komma: echo "Dette er ", "en tekst."; Hvis du forsøker å gi flere argumenter mens du bruker metode nummer to vil du imidlertid få en feilmeldingen av typen parse error (unexpected ','). print Kommandoen print er veldig lik echo, men har to viktige forskjeller. print kan under ingen omstendigheter akseptere mer enn ett argument. Print, i motsetning til echo, returnerer en verdi som sier om print-kommandoen lyktes. Verdien som returneres vil være 1 hvis utførelsen lyktes og 0 hvis den ikke lyktes. Det er svært, svært skjeldent at en print-kommando ikke lykkes, men i sære tilfeller som hvis brukeren har lukket nettleseren kan funksjonen være nyttig. Syntaksen til print er slik:
22 22 Kapittel 2. Syntaks, variabler og ut-data print("dette er en tekst"); //Skriver ut en streng print( ); //Skriver ut et tall Kapittel 2 av denne innføringen nærmer seg slutten. Nå er vi endelig på vei over kneika, så snart kan vi begynne med det som virkelig er gøy. I påvente av neste kapittel vil jeg anbefale alle og enhver å teste ut forskjellige ting. Er det noe du er usikker på? Test det ut! Sammendrag I dette kapittelet har vi sett at PHP er et tilgivende språk med en syntaks liknende programmeringsspråket C. Kodesekvenser i PHP starter med og ender med. Et semikolon benyttes for å indikere at en konstatering er ferdig. Videre bruker vi /* */ for kommentarer over flere linjer, og # eller // for kommentarer på én linje. Variabler benyttes til å mellomlagre informasjon. En variabel defineres slik: $variabelnavn = "variabeltekst";. Hva slags type (desimaltall, heltall, strenger osv.) variabelen er trengs i utgangspunktet ikke å defineres. Forskjellene mellom apostrof (') og anførselstegn (") kan virke små, men er i virkeligheten store. En variabel vil ikke skrives ut hvis man benytter apostrof, i tillegg til at anførselstegn har en god del tegn som erstattes med andre karakterer, som \n og \r. I utgangspunktet benytter man echo-funksjonen til å sende ut-data til nettleseren. Man kan også benytte print, som gir tilbakemelding på om utførelsen var vellykket. I neste kapittel vil vi se på hvordan vi sammenlikner flere verdier, og utføre handlinger basert på utfallet. I mellomtiden lek deg litt for å bli kjent med PHP.
23 Kapittel 3. Kontrollering av verdier 23 Kapittel 3. Kontrollering av verdier Vi ser på hvordan vi kan utføre ulike handlinger basert på betingelser. Er du en av mange som har lekt litt med HTML, men savner mer funksjonalitet? I denne artikkelserien vil vi lære deg å bruke PHP og MySQL til å lage dynamiske webløsninger, slik at du kan ta webutviklingen til et nytt nivå. For å få best mulig utbytte av denne innføringen er det en fordel at du kan HTML og har en viss kjennskap til programmering. Dette er imidlertid ikke et krav - du skal kunne skjønne det meste uten noen som helst bakgrunnskunnskap. I kapittel 1 av denne guiden så vi på hva PHP er, historien til PHP og hvordan PHP installeres. Til slutt så vi på litt enkel programmering som "hello world" og inkludering av filer. I kapittel 2 så vi på syntaksen til PHP og hvordan man behandler variabler. Til slutt så vi litt på hvordan man sender ut-data fra PHP, som echo og print. I dette kapittelet vil vi se på hvordan vi kan kontrollere og sammenlikne verdier, for deretter å utføre handlinger basert på utfallet. Du vil lære å skrive skript som har handlinger med betingelser - altså kommandoer som kun vil bli utført hvis betingelsene ligger til rette. Fra og med dette kapittelet har jeg gjort en liten forandring - kodeeksemplene vil ikke lenger inkludere start- og slutt-markeringen for PHP ( og ). Skal du teste eksemplene i praksis må du altså selv legge til dette. Husk at dokumentet må lagres med filendelsen.php. if-else og boolske konstanter Det er vanskelig å skrive interessante skript uten å la utførelsen til skriptet avhenge av noe. For å lage skikkelige skript må vi kunne utføre kontroller, for deretter å utføre handlinger basert på utfallet. Det finnes to hovedtyper av kontroller - grener (branches) og sløyfer (loops). En gren utfører én enkel kontroll, og avhengig av utfallet velger den hvilken vei den skal gå. En sløyfe derimot, utfører denne kontrollen flere ganger. Etter at kontrollen er utført vil den begynne på kontrollen igjen, inntil ønsket antall kontroller er gjort. if-else if-else er den vanligste formen for å utføre en kontroll. Syntaksen er slik: if (test av uttrykk) Utfør visse handlinger else Utfør noen andre handlinger Her blir først en test av ett eller flere uttrykk utført. Hvis uttrykket/uttrykkene stemmer, vil den boolske verdien TRUE returneres, og handlingene vil bli utført deretter. Er imidlertid uttrykket/uttrykkene usanne, slik at verdien FALSE returneres, vil ikke kommandoen(e) som står mellom klammene ( og ) utføres. Det er her else kommer inn i bildet. Else sjekker ikke om noen uttrykk stemmer, den bare utfører én eller flere kommandoer som et følge av at testen av uttrykket/uttrykkene avslørte at uttrykket/uttrykkene var usanne.
24 24 Kapittel 3. Kontrollering av verdier Man trenger strengt tatt ikke bruke klammene i alle tilfeller, men det er god programmeringsskikk å gjøre det, for lesbarhetens skyld. For eksempel kan det bli vanskelig å finne ut hvilken if-spørring en else hører til hvis det ikke er markert med klammer. Boolske konstanter For å se om et uttrykk stemmer bruker vi operatoren if. Deretter kan vi bruke operatoren else, som utfører en eller flere kommandoer hvis uttrykket ikke stemmer. Den letteste formen for et uttrykk er de boolske verdiene TRUE og FALSE. if (TRUE) echo "Dette vil alltid vises"; else echo "Dette vil aldri vises"; Som vi ser utfører vi en kontroll ved hjelp av if. Stemmer ikke det første uttrykket vil programmet automatisk hoppe ned til else og utføre kommandoen(e) der. Skulle vi ha skrevet dette så vi enkelt kunne forstått det hadde det sett slik ut: HVIS SANT SKRIV "Dette vil alltid vises" ELLERS SKRIV "Dette vil aldri vises" Vi kan også utføre en motsatt kontroll, der vi kjører kontrollen if (FALSE): if (FALSE) echo "Dette vil aldri vises"; else echo "Dette vil alltid vises"; Dette vil da være det tilsvarende "på norsk": HVIS USANT SKRIV "Dette vil aldri vises" ELLERS SKRIV "Dette vil alltid vises" Eksemplene over har heller liten nytte i et virkelig skript - de er kun ment for å gi en enkel innføring. På neste side vil vi se på eksempler som du vil få mer bruk for i praksis. Sammenlikne verdier Den mest elementære formen for betingelser er å sammenlikne to verdier. I det følgende eksempelet sammenlikner vi to heltall.
25 Kapittel 3. Kontrollering av verdier 25 if (3 == 3) echo "Uttrykket stemmer"; else echo "Uttrykket stemmer ikke"; Her gjennomfører vi en kontroll av de to heltallene "3" og "3", med operatoren ==, som betyr "er lik". Kjører vi dette skriptet vil vi selvsagt få verdien "Uttrykket stemmer". Hadde ikke uttrykket stemt ville vi fått verdien "Uttrykket stemmer ikke". Vi kan selvsagt gjennomføre denne kontrollen med variabler. Se det følgende eksempelet: $variabel1 = 3; $variabel2 = 3; if ($variabel1 == $variabel2) echo "Uttrykket stemmer"; else echo "Uttrykket stemmer ikke"; Hvis vi derimot bytter ut == med!= vil vi få et helt annet resultat.!= betyr nemlig "ikke lik". $variabel1 = 3; $variabel2 = 3; if ($variabel1!= $variabel2) echo "Uttrykket stemmer"; else echo "Uttrykket stemmer ikke"; Det finnes en rekke slike sammenliknings-operatorer. Her er en komplett liste: == (er lik) - Sann hvis de to argumentene er like hverandre!= (ikke lik) - Sann hvis de to argumentene ikke er like hverandre < (mindre enn) - Sann hvis det første argumentet er mindre enn det andre argumentet > (størren enn) - Sann hvis det første argumentet er større enn det andre argumentet <= (mindre enn eller lik) - Sann hvis det første argumentet er mindre enn eller likt det andre argumentet >= (større enn eller lik) - Sann hvis det første argumentet er større enn eller likt det andre argumentet === (identisk) - Sann hvis de to argumentene er like hverandre, og av samme type (altså må begge være strenger, eller begge må være heltall osv.)
26 26 Kapittel 3. Kontrollering av verdier Det er viktig å merke seg forskjellen mellom =, == og ===. = brukes som kjent til å sette variabler. Kjører du følgende skript: $a = 1; $b = 2; if ($a = $b) (...)...vil du sette $a til den samme verdien som $b. I tillegg vil uttrykket bli sett på som sant (TRUE) så lenge $b er satt til en verdi. I tilfellet over skulle vi ha brukt ==, eventuelt === hvis vi ønsket å være sikre på at begge variablene er av samme type. Logiske operatorer En logisk operator er en operator som forbinder logiske uttrykk (som boolske uttrykk) til å produsere nye boolske verdier (TRUE eller FALSE). Med andre ord forbinder logiske operatorer flere uttrykk sammen, og utfører funksjoner avhengig av utfallet av uttrykkene. Som i alle programmeringsspråk finnes det i PHP en rekke logiske operatører. Først ser vi på &&, på engelsk kalt "and" ("og"). $number1 = 5; $number2 = 10; $number3 = 12; $number4 = 15; if ($number1 < $number2 && $number4 > $number3) echo "Uttrykkene stemmer"; else echo "Uttrykkene stemmer ikke"; I dette eksempelet bruker vi den logiske operatoren && for å indikere at både uttrykket "5 er mindre enn 10" og uttrykket "15 er mer enn 12" må stemme for at kontrolleringen skal returnere TRUE, og dermed gjennomføre kommandoen(e). I dette skriptet stemmer begge uttrykkene, og vi vil derfor få teksten "Uttrykkene stemmer". På samme måte kan vi gjennomføre en kontroll som kun krever at én av uttrykkene skal stemme, ved hjelp av (på engelsk "or", norsk "eller"). $number1 = 5; $number2 = 10; $number3 = 15; $number4 = 12; if ($number1 < $number2 $number4 == $number3) echo "Ett eller flere av uttrykkene stemmer"; else echo "Ingen av uttrykkene stemmer";
27 Kapittel 3. Kontrollering av verdier 27 I dette eksempelet stemmer uttrykket "5 er mindre enn 10", mens uttrykket "12 er lik 15" ikke stemmer. indikerer imidlertid at det er nok at ett av uttrykkene stemmer, og vi vil derfor få returnert teksten "Ett eller flere av uttrykkene stemmer". Vi kan også sette sammen flere logiske operatorer i en og samme if-gren. Skal vi gjøre dette gjøres det på følgende måte: $var1 = 1; $var2 = 1; $var3 = 2; if (($var1 == $var2 && $var2 < 1) ($var1!= $var3 && $var3 > $var2)) (...) (Hvor (...) representerer det videre skriptet.) Her er en liste over alle logiske operatorer i PHP5: and - Er sann hvis begge uttrykkene stemmer or - Er sann hvis minst ett av uttrykkene stemmer xor - Er sann hvis ett av (men ikke begge) uttrykkene er sanne && - Akkurat samme som and - Akkurat samme som or! - Er sann hvis uttrykket til høyre er usant Else if Hva hvis vi skal utføre en rekke kontrolleringer, og hvis den første kontrolleringen viser seg å være sann, så er resten av kontrolleringene unødvendige? Til nå har vi kun brukt if og else, og det er tungvint å bruke i et slikt tilfelle. La meg introdusere dere for else if. $var1 = 10; $var2 = 20; $var3 = 30; if ($var1 > $var2) (...) else if ($var2!= $var3) (...) else (...) Dette burde være rimelig selvforklarende, men jeg tar allikevel en kort forklaring. Hvis resultatet av den aller første kontrollen viser seg å være usann, så vil den neste kontrollen utføres. Viser det seg imidlertid at den første kontrollen er sann vil ikke else if-kontrollen bli utført. PHPparseren vil altså hoppe over den.
28 28 Kapittel 3. Kontrollering av verdier Sammenlikne verdier som ikke er heltall Til nå har vi kun sett på hvordan man sammenlikner tall. Men hva hvis man vil sammenlikne andre former for variabler - for eksempel strenger? if ($username == "Stupidguest") echo "Du har et idiotisk brukernavn."; Se, det var ikke verre enn det! Vi bare la til noen anførselsteng for å markere at det er snakk om en streng (eng: string). Når det gjelder sammenlikning mellom heltall og desimaltall, så gjør PHPparseren selv en god jobb med å endre typen slik at alle tallene er desimaltall, slik at de kan bli sammenliknet. For eksempel vil 50 da bli Med andre ord bruker vi her akkurat samme metode som når vi sammenlikner to heltall. Switch Hvis vi har en rekke else if-kontrolleringer kan det lønne seg å bytte til switch. Det er lettere å forklare dette med et skikkelig eksempel. Som det sies, et bilde sier mere enn tusen ord. Bare at i dette tilfellet er det et par kodeksempler. if ($dag == 1) echo "Mandag"; else if ($dag == 2) echo "Tirsdag"; else if ($dag == 3) echo "Onsdag"; else if ($dag == 4) echo "Torsdag"; else if ($dag == 5) echo "Fredag"; else if ($dag == 6) echo "Lørdag"; else if ($dag == 7) echo "Søndag"; (Du ser sikkert at jeg har kuttet vekk noen linjeskift. Dette er gjort for å spare plass, og som du lærte i kapittel 2 bryr ikke PHP seg om linjeskift.) Som vi ser skriver dette skriptet ut navnet på ukedagen, avhengig av hvilket nummer det er (for å få dette skriptet til å fungere måtte selvsagt variabelen dag vært definert). Dette kan gjøres på en bedre, og i manges øyne, lettere måte med switch. switch($dag) case 1: echo "Mandag"; break; case 2: echo "Tirsdag"; break; case 3: echo "Onsdag"; break; case 4: echo "Torsdag"; break; case 5: echo "Fredag"; break; case 6: echo "Lørdag"; break; case 7: echo "Søndag"; break;
29 Kapittel 3. Kontrollering av verdier 29 Denne kodebiten gjør nøyaktig det samme som vårt tidligere eksempel. Lett, ikke sant? Det er imidlertid én viktig ting du må huske på når du benytter switch - du må alltid avslutte kommandoene med break;. Hvis du glemmer å gjøre dette, og dag er satt til for eksempel 5, vil kommandoen(e) i case 5, case 6 og case 7 bli utført. Switch med strenger Switch kan selvsagt brukes i andre tilfeller enn der variablen(e) vi bruker er heltall. La oss se på hvordan det gjøres med strenger (strings), altså tekst. switch ($mat) case "ostekake": echo "Jeg vil også ha ostekake!"; break; case "lasagne": echo "Lasagne, du. Du er den typen altså."; break; case "pizza": echo "Pizza hadde virkelig gjort seg nå."; break; Avhengig av hva variabelen mat er satt til, så vil den respektive teksten bli vist. Men hvordan kan man få til else i en switch-kontrollering? Dette gjøres ved hjelp av default. Hvis ingen av uttrykkene i switch viser seg å være sanne, vil visse funksjoner bli utført, altså akkurat som ved bruk av else. default trengs ikke å avsluttes med break, men må plasseres til slutt. switch ($foo) case "bar": echo "Foobar! Let's dance!"; break; case "foobar": echo "Fubar! Itt' no dansing for deg."; break; default: echo "Denne teksten vil bli vist hvis \$foo ikke er definert."; (Teit eksempel, men du forstår nok meningen.) Man kan selvsagt også utføre tester med logiske operatører ved bruk av switch. switch (TRUE) case $foo == $bar: echo "Hurra, hurra!"; break; (...) Løkker - while Det vi har sett på til nå er nyttig, men det har selvsagt sine begrensninger. Nå har vi endelig kommet oss til løkker (eng: loops), og det er nå moroa for alvor kan starte.
30 30 Kapittel 3. Kontrollering av verdier Den letteste formen for en løkke er while, som vil utføre en eller flere kommandoer helt til det stoppes. while (TRUE) echo "Oh, God! Denne løkken fortsetter i all evighet!"; Kjører vi denne kodebiten vil altså teksten "Oh, God! Denne løkken fortsetter i all evighet!" bli skrevet ut (jepp, du gjettet riktig) uendelig antall ganger. En while-løkke vil altså utføre kommandoen(e) inntil uttrykket er usant. $nummer = 1; while ($nummer <= 10) echo "Dette er linje nummer $nummer<br>"; $nummer++; Her gir vi variabelen nummer sin egen verdi pluss 1 etter hver gang teksten blir skrevet ut. $nummer++ vil gjøre samme nytten som $nummer = $nummer + 1 (mer om dette i et senere kapittel). Som vi ser vil while-løkken utføre kommandoene helt til uttrykket ikke stemmer, altså helt til det er skrevet ut 10 linjer. Prøv selv og se! do-while do-while-konstruksjonen er lik som while, bortsett fra at kontrolleringen foregår på slutten av løkken. Syntaksen er slik: do funksjoner(er) while (uttrykk); Funksjonene vil bli utført én gang, og deretter vil uttrykket/uttrykkene i while-løkken bli testet, og om det viser seg å være sant (returnerer verdien TRUE) vil den utføre funksjonene i do inntil uttrykket/uttrykkene viser seg å være usanne. $nummer = 1; do echo "Dette er linje nummer $nummer<br>"; $nummer++; while ($nummer <= 10); Mer om løkker - for Den mest kompliserte løkketypen er for, som har følgende syntaks: for (uttrykk1; uttrykk2; uttrykk3) funksjon(er) Først blir uttrykk1 utført, og det kun én gang. Denne inneholder normalt deklarering av en variabel. Deretter blir selve sjekken av uttrykket utført (uttrykk2). Viser dette uttrykket seg å være usant vil for-løkken stoppes. Er den sann fortsetter den, og utfører uttrykk3. Det høres kanskje vanskelig ut, men se på det følgende eksempelet. Vi har tatt utgangspunkt i det samme som vi gjorde ved eksemplene på while- og do-while-eksemplene.
31 Kapittel 3. Kontrollering av verdier 31 for ($nummer = 1; $nummer <= 10; $nummer++) echo "Dette er linje nummer $nummer<br>"; Kjører vi dette vil vi få akkurat samme utfall som ved de forrige eksemplene. Prøv selv! La oss bruke det i praksis! Eksemplene vi nå har sett på fungerer fint, men de har liten nytte i praksis. La oss bruke det vi har lært i praksis til å estimere kvadratroten av et tall, la oss si 81. Riktignok har PHP en fin funksjon som selv sier hva kvadratoroten er (sqrt()), men det er mye morsommere å gjøre det selv. Gjetningen starter med at "1" er kvadratroten, og forbedrer etter hver kjøring gjetningen. For å gjøre dette må vi kunne litt grunnleggende matematikk i PHP. Det er selvsagt svært enkelt. * indikerer multiplikasjon (ganging), / indikerer divisjon (deling), - indikerer minus, osv. $nummer = 81; $gjett = 1.0; $presisjon = ; $gjett_rot = $gjett * $gjett; while (($gjett_rot - $nummer > $presisjon) or ($gjett_rot - $nummer < - $presisjon)) echo "Jeg gjetter at kvadratroten av $nummer er $gjett<br>"; $gjett = ($gjett + ($nummer / $gjett)) / 2; $gjett_rot = $gjett * $gjett; echo "$gjett er kvadratroten av $gjett_rot"; Kjører vi dette skriptet skal det se ut noe som dette: Dette kan imidlertid virke litt vanskelig og uoversiktlig for mange, spesielt de som ikke har så mye kjennskap til matematikk. Studer koden nøyere, og test gjerne ut forskjellige ting selv! break og continue Den vanlige måten å stoppe en løkke fra utførelse er at uttrykket/uttrykkene viser seg å være usanne, som vi har sett til nå. break og continue muliggjør imidlertid en alternativ måte å stoppe løkken fra utførelse. break-kommandoen avslutter hele den aktuelle løkken, mens continue-kommandoen hopper over utførelsen av de neste kommandoene. La oss teste om tall er oddetall eller ikke. Denne testen kjøres slik: $variabel % 2 (% er operatoren for modulo), og variabelen vil deretter få en verdi basert på om den er et oddetall eller ikke. Er det et oddetall vil variabelen få verdien 1, mens hvis det ikke er et oddetall vil den få verdien 0.
32 32 Kapittel 3. Kontrollering av verdier for ($tall = 1; $tall < 10; $tall++) if ($tall % 2!= 0) break; echo $tall; Eksempelet over vil faktisk ikke returnere noe som helst. Dette er fordi $tall er satt til 1, og som vi vet er det et oddetall. Break vil dermed sette en effektiv stopper for hele løkken. Hadde vi imidlertid satt verdien til 2 hadde vi fått skrevet ut verdien av variabelen (2), ettersom 2 ikke er et oddetall. Ved neste kjøring av løkken ville imidlertid verdien vært 3, ettersom vi i for-løkken setter verdien av variabelen til sin egen verdi + 1. Verdien blir dermed 3, som er et oddetall. Løkken ville altså ha blitt stoppet av break ved andre kjøring. for ($tall = 1; $tall < 10; $tall++) if ($tall % 2!= 0) continue; echo $tall; Ved første utførelse av løkken vil variabelen ha verdien 1, som er et oddetall, og det blir dermed ikke vist. Ved andre utførelse er imidlertid verdien 2, som ikke er et oddetall. Når løkken er ferdig med utførelsen vil vi ha fått vist tallene 2, 4, 6 og 8. Dette er altså de tallene som ikke er oddetall mellom 1 og 9. Som sagt hopper continue-kommandoen over utførelsen av de neste kommandoene, men lar løkken kjøre på nytt. Vi kan nå benytte det eksakt samme eksempelet som over, bare at vi har byttet ut break med continue. Vi kan nå bruke det vi kan i praksis til å konstruere et skript som vil vise alle primtall (tall som kun er delelig med seg selv og 1) opp til et visst tall. Til akkurat dette skriptet er ikke continue nødvendig.
33 Kapittel 3. Kontrollering av verdier 33 // Grensen for hva som er den høyeste verdien vi kan teste $grense = 300; // Hvilken verdi testen starter på $test = 2; while (TRUE) $testdivisjon = 2; // Hvis vi har oversteget den høyeste verdien vi skal teste, // stopp skriptet if ($test > $grense) break; while (TRUE) if ($testdiv > sqrt($test)) // Skriv ut og stopp løkken echo "$test "; break; // Sjekk om $test er mulig å dividere med $testdivisjon if ($test % $testdivisjon == 0) break; $testdivisjon++; $test++; Kjører vi dette skriptet skal vi få følgende tall vist: Det viktige å merke seg her er at break kun vil stoppe den nærmeste løkken den står "inne i". Den vil altså ikke avslutte hoved-løkken, men bare sin egen løkke. Se litt på skriptet, og du skjønner det nok. Som du sikkert ser har vi her benyttet PHP-funksjonen sqrt() til å sjekke kvadratroten. Akkurat som ved vårt skript som estimerer kvadratrot kan dette skriptet være litt vanskelig å forstå for mange. Jeg kan bare gjenta meg selv - les koden nøyere og test ut ting selv, så går det nok bra! Uendelige løkker Som vi så i vårt aller første eksempel med while-løkken er det fullt mulig å konstruere løkker som fortsetter i all evighet. Som standard er max_execution_time, altså den maksimalt tillate tiden et skript har på å bli ferdig med kjøringen, satt til 30 sekunder i php.ini (PHPs konfigurasjonsfil). Et skript som overksrider denne begrensingen vil resultere i en feilmelding som ser slik ut:
34 34 Kapittel 3. Kontrollering av verdier Fatal error: Maximum execution time of 30 seconds exceeded in [fil] on line [linje] Med andre ord vil en uendelig løkke som standard bli stoppet etter ett halvt minutt, slik at den ikke spiser opp ressursene til serveren. I enkelte tilfeller kan det imidlertid være nyttig, om ikke nødvendig, å sette denne tidsbegrensingen høyere. Dette bruker vi funksjonen ini_set() til. Ved utførelse vil denne funksjonen midlertidig endre en eller flere av konfigurasjonene i php.ini. Med andre ord vil ikke disse endringene påvirke andre skript. La oss si at vi har en enorm løkke som ved kjøring vil overstige tidsbegrensingen. Dette er, selv på svakere servere, relativt vanskelig å få til, men skriver man for eksempel store filer til disken er det godt mulig å overstige denne begrensningen. Vi benytter da ini_set("max_execution_time", "120");. I eksempelet vårt definerer vi at maks tid skriptet har for utførelse vil være 120 sekunder. Alternativ kontroll-syntaks Forskjellige programmeringsspråk har forskjellig syntaks, men PHP forsøker å gi muligheter for mange typer syntaks, slik at overgangen fra et språk til PHP skal være så lite smertefull som mulig. Til nå har vi sett på den normale metoden å utføre kontroller med PHP, men vi kan også bruke en mer utradisjonell metode. La oss gå rett på sak, og se hvordan en enkel if-elsekontroll kan skrives på en annen måte. if ($tall == 0): echo "$tall er 0"; elseif ($tall == 1): echo "$tall er 1"; endif; Skulle vi ha skrevet en while-løkke på denne måten ville det sett slik ut: $nummer = 1; while ($nummer <= 5): echo "Dette er linje nummer $nummer<br>"; $nummer++; endwhile; Så hvorfor bruke dette? Det finnes egentlig ingen god grunn - ytelsesmessig skal de være omtrent helt like. I tidligere versjoner av PHP ble kontroller skrevet på denne måten, og fordi brukere er vant med denne syntaksen både fra andre programmeringsspråk og fra tidligere versjoner av PHP er det fortsatt mulig å skrive på denne måten. Det er med andre ord et spørsmål om smak. Oppsummering I kapittel 3 har vi endelig fått begynne på mer morsomme ting. Vi så først på den svært mye brukte if-else-konstruksjonen, som utføres slik: if (test av uttrykk) Utfør visse handlinger else Utfør noen andre handlinger
35 Kapittel 3. Kontrollering av verdier 35 Videre har vi sett på sammenliknings-operatorer som == og <=, og lært den svært viktige forskjellen mellom =, == og ===. Logiske operatorer forbinder logiske uttrykk, slik at vi kan foreta kontroller med flere uttrykk i én og samme kontroll. Eksempler på logiske operatorer er && og. Vi så mye på switch, som trist nok er et nærmest glemt kapittel hos PHP. switch kan gjøre lange if-else-kontroller lettere og i mange øynes mer oversiktlig. Vi lærte om forskjellige typer løkker, som har den egenskapen at de gjennomfører kontrollen opp til uendelig antall ganger. Skulle man lage en løkke som foregår uendelig vil den automatisk bli stoppet av PHPs 30-sekundersgrense, med mindre annet er spesifisert. De av dere som har brukt PHP endel før vil nok legge merke til at jeg ikke har forklart foreach. Det kommer av den enkle grunnen at foreach brukes til å kjøre løkker på arrays, noe jeg enda ikke har forklart hva er for noe. Jeg skal imidlertid forklare hvordan man bruker foreach i kapittel 5. I neste kapittel vil vi se på lister.
36 36 Kapittel 4. Lister Kapittel 4. Lister Vi fortsetter vår innføring med å ta for oss lister. Lister, gjerne også kjent som arrays, brukes til å lagre indekssortert data for hurtige oppslag. Akkurat det sier deg gjerne ikke så mye, men definisjonen er svært vag fordi den omfatter svært mye. Den enkleste måten å tenke på en array på, er som en nummerert liste. Men, på grunn av fleksibiliteten til PHP, trenger man ikke bruke tall for å nummerere lista! Forvirret? I dette kapittelet skal vi gå gjennom de vanligste bruksområdene av arrays, og vanlige operasjoner å gjøre på dem. Opprette arrays Som svært mange ting i PHP finnes det flere måter å lage arrays på. Men først og fremst; en array behandles på svært mange måter akkurat som en annen variabel i PHP. Array er rett og slett en ekstra datatype, som lar deg gjøre litt flere ting enn med vanlige variabler. $farger = Array("Blå", "Rød", "Grønn"); print_r($farger); En av de vanligste måtene å opprette en array på er slik som over. Funksjonen Array() (vi skal snakke mer om funksjoner i neste kapittel) tar inn en rekke verdier som arrayen vil bestå av. print_r() skriver ut innholdet av en variabel på en annen måte enn echo gjør. Om du kjører dette skriptet får du ut følgende data; Array ( [0] => Blå [1] => Rød [2] => Grønn ) Den første linjen indikerer at variabelen vi skrev ut er en array. De to parentesene viser hva som er innholdet i denne arrayen. [0] beskriver indeks 0, og som inneholder verdien "Blå". Indeks 1 inneholder "Rød", og indeks 2 inneholder "Grønn". Det er verdt å merke seg at den første indeksen begynner på 0 og ikke på 1 som gjerne er mer naturlig for mennesker. $farger = Array("Blå", "Rød", "Grønn"); $farger[0] = "Turkis"; $farger[] = "Rosa"; print_r($farger); To små tillegg til funksjonen over viser at vi kan bytte ut fargen som er indeksert som nummer 0 ved å overskrive $farger[0]. Du kan også få tak i innholdet i indeks 0 ved å bruke samme notasjon. Vi kan også legge til en ekstra farge på slutten av arrayen ved å bruke $farger[], som automatisk legger til neste tall. I dette tilfellet ville $farger[3] vært det samme, men å bruke tomme klammer gjør at PHP selv finner ut hvilken indeks den skal sette inn. Under ser du resultatet av skriptet over.
37 Kapittel 4. Lister 37 Alternativ oppretting Den alternative måten å starte arrays på, er å bare begynne å jobbe direkte med klammenotasjonen. Arrayen ovenfor kan like lett lages ved å gjøre følgende: Variabelen $farger opprettes da som en array fra den blir brukt første gang. Man kunne også satt inn tallene direkte. Løkker og arrays Arrays blir svært ofte benyttet for å bla gjennom en rekke med data, og liste dem opp for nettleseren, eller å gjøre utregninger med verdiene. Det finnes flere måter å gjøre dette på, og alle involverer løkker, som vi snakket om i kapittel 3. En av de letteste å bruke når det er snakk om arrays, er foreach, som vi ikke har nevnt før. foreach Array ( [0] => Turkis [1] => Rød [2] => Grønn [3] => Rosa ) $farger[] = "Blå"; $farger[] = "Rød"; $farger[] = "Grønn"; foreach-løkker, direkte oversatt til "for hver"-løkker, blar gjennom hvert eneste element i arrayen, og lar deg gjøre operasjoner på disse elementene. Et enkelt eksempel følger; $farger = Array("Rød", "Grønn", "Blå"); foreach ($farger as $farge) echo $farge."<br/>"; Dette skriptet skriver ut "Rød", "Grønn" og "Blå" på hver sin linje. foreach-delen sier at man skal bruke $farger-arrayen, og kalle hvert element for $farge. Inne i løkken kan vi da skrive ut $farge, og den variabelen endrer verdi til en ny farge fra arrayen hver gang løkken gjennomgås. Det finnes også en utvidet versjon av foreach, som lar deg få tilgang på nøkkelen for hvert element i tillegg til dataene. Da blir det seende slik ut; $rangeringer = Array(1 => "Gull", 2 => "Sølv", 3 => "Bronsje", 10 => "Taper!"); foreach ($rangeringer as $indeks => $verdi) echo $indeks.". ".$verdi."<br/>"; Legg merke til at vi her definerer indeks 1, 2, 3 og 10, og at foreach bare skriver ut disse. foreach-løkken fyller nå også inn 2 variabler, $indeks og $verdi, som blir fylt med henholdsvis indeksverdien og dataverdien for den gjennomkjøringen.
38 38 Kapittel 4. Lister Merk at dersom du forsøker å overskrive $verdi i foreach-løkken, vil ikke $rangeringer bli påvirket av det. Det er fordi $verdi bare er en kopi av verdien, og ikke en peker til verdien i $rangeringer. Dersom du ønsker å endre arrayen $rangeringer, blir du nødt til å bruke indeksen direkte i arrayen; for $rangeringer[$indeks] = "ostekake";. Dersom du har en array med uavbrutt sekvensielt nummererte indekser, kan du bruke en forløkke for å bla gjennom den. Det er ofte gjerne enklere å benytte seg av foreach, men likevel er for-løkker noe av det vanligste å se når det gjelder gjennomsøking av arrays. $rangeringer = Array(1 => "Gull", 2 => "Sølv", 3 => "Bronsje"); for ($i = 1; $i <= 3; $i++) echo $i.". ".$rangeringer[$i]."<br/>"; Det er svært lite spesielt med hvordan for-løkker fungerer i forbindelse med arrays, så denne kommenteres svært lite. Hva hadde forresten skjedd her om vi hadde hatt den samme $rangeringer-variabelen som i kodeeksempelet ovenfor? Andre løkker Det finnes selvsagt også andre måter å bla gjennom arrays på, en av dem er syntaksen hvor man bruker en while-løkke med noen spesielle array-funksjoner. Denne er funksjonelt identisk med foreach, og du kan lese om den på manualens side om foreach 13. Mer om indekser Indeksene, gjerne også kjent som nøklene eller keys, i en array kan også være andre ting enn heltall. Til nå har vi holdt oss eksklusivt til å bruke heltall som indekser, men det er ingenting i veien for at indekser kan være tekst, men de kan ikke være flyttall eller objekter. Dette gjør arrays i PHP svært fleksible, og arrays er optimert for flere forskjellige bruksområder. Det betyr at de uansett er svært raske å slå opp i, å sette inn verdier i og å oppdatere verdier, og dette er gjerne noe man ikke trenger å bekymre seg for i daglig bruk. Arrays trenger ikke være sortert etter indeksene, men blir normalt sortert etter rekkefølgen ting blir satt inn i. Så, dersom du blar gjennom en array ved hjelp av foreach (mer om denne senere) vil du gjerne ofte oppleve at indeks 3 kan komme før indeks 1. Det gjør at vi gjerne må sortere arrays med jevne mellomrom. $rangeringer = Array(10 => "Taper!", 2 => "Sølv", "a" => "Gull", 3 => "Bronsje"); foreach ($rangeringer as $indeks => $verdi) echo $indeks.". ".$verdi."<br/>"; 13
39 Kapittel 4. Lister 39 Koden ovenfor demonstrerer mye av dette. Her ser du at innholdet i arrayet er lagt til i rekkefølgen 10, 2, "a", 3, og foreach-løkken vil derfor skrive ut dette i den rekkefølgen. Legg også merke til at en av indeksene er en string ("a"), og at dette ikke er noe problem for PHP. En ting som er spesielt med PHP, i alle fall i forhold til mange andre programmeringsspråk, er at arrays er assosiative. Det betyr at dersom en verdi har indeks 4, og du sletter element 0, 1, 2 og 3 i arrayen, vil fremdeles den samme verdien ligge lagret i indeks 4. Det gjør at traversering med en for-løkke kan føre til feil dersom du har slettet noe i arrayen. Sortering Det finnes en hel rekke interne funksjoner i PHP som lar deg sortere arrays på ulike måter. Disse funksjonene blir som oftest brukt før man skal gjennomgå en liste med blant annet foreachløkker. Her er en kort beskrivelse; sort() Denne funksjonen sorterer en array basert på verdiene i arrayen. Indeksene blir byttet ut med heltall som starter på null. Om verdiene i arrayet er strenger, vil de ende opp i alfabetisk rekkefølge. Legg merke til at sort() endrer selve variabelen som du sender inn, og dette gjelder også de andre sorteringsfunksjonene. Resultatet av en gjennomkjøring blir i dette tilfellet (legg merke til at verdiene er alfabetisk sortert); asort() 10. Taper! 2. Sølv a. Gull 3. Bronsje $rangeringer = Array(10 => "Taper!", 2 => "Sølv", "a" => "Gull", 3 => "Bronsje"); sort($rangeringer); print_r($rangeringer); Array ( [0] => Bronsje [1] => Gull [2] => Sølv [3] => Taper! ) En a i begynnelsen av funksjonsnavnet står for assosiativ. Det betyr at de originale indeksene blir beholdt, og at det bare er rekkefølgen på elementene som blir endret. Ellers sorterer asort() i samme rekkefølge som sort(). Ved å bytte ut funksjonkallet i eksempelet ovenfor med asort() vil vi få følgende resultat; Array ( [3] => Bronsje [a] => Gull [2] => Sølv [10] => Taper! )
40 40 Kapittel 4. Lister rsort() og arsort() En r i begynnelsen av funksjonsnavnet står for reversert. Det betyr at strenger blir sortert i reversert alfabetisk rekkefølge. Dette kan kombineres med assosiativ sorteringer, og dermed får vi to funksjoner rsort() og arsort(). Her er resultatet av rsort; Slik blir arsort(); ksort() og krsort() Om du vil sortere en array etter indeksene i arrayen, bruker du funksjonene som begynner på k. ksort() og krsort() sorterer nøklene alfabetisk og reversert alfabetisk, og tar selvsagt vare på indeksene. Resultatene fra eksemplene ovenfor blir som følger, først for ksort(); Legg merke til at "a" kommer etter heltallet 10. Deretter krsort(); Vanlige operasjoner Det er ofte man trenger å fjerne elementer fra en array, finne indeksen til spesifikke verdier, og lignende. PHP har en rekke innebygde funksjoner for å gjøre dette, og her presenterer vi noen av dem. I manualen finner du en rekke andre slike funksjoner, vi har kun valgt ut noen av de viktigste. count() Array ( [0] => Taper! [1] => Sølv [2] => Gull [3] => Bronsje ) Array ( [10] => Taper! [2] => Sølv [a] => Gull [3] => Bronsje ) Array ( [2] => Sølv [3] => Bronsje [10] => Taper! [a] => Gull ) Array ( [a] => Gull [10] => Taper! [3] => Bronsje [2] => Sølv ) count() gir deg antallet elementer i arrayet. Svært nyttig om du har en kontinuerlig sekvensielt nummerindeksert array.
41 Kapittel 4. Lister 41 array_reverse() array_reverse() snur arrayet motsatt vei, slik at de første verdiene kommer til slutt. Den tar en eller to parametre, den første er arrayet som skal snus, den valgfrie nummer to angir om indeksene skal bevares. Den nye arrayen kommer ut som returverdi. array_key_exists() og in_array() array_key_exists() sjekker om en indeks finnes i en array, og returnerer en boolsk verdi. Den første parameteren er indeksen som den skal prøve å finne, og den andre angir arrayet. in_array() sjekker om en verdi finnes i en array, og returnerer en boolsk verdi. Den første parameteren angir verdien som man skal prøve å finne, den andre angir arrayet det skal søkes i. array_rand() $array = Array("Ola", "Lars", "Per", "Nils"); for ($i = 0; $i < count($array); $i++) echo $array[$i]."<br/>\n"; $array = Array("Ola", "Lars", "Per", "Nils"); if (array_key_exists(2, $array)) echo "Fant indeks 2!<br/>"; if (in_array("ola", $array)) echo "Fant Ola!<br/>"; array_rand() plukker et eller flere elementer tilfeldig fra et array, og returnerer enten en enkel verdi (om du plukker et element) eller en array. Verdiene du får ut er indeksene til de tilfeldige elementene, ikke verdiene. Parameter nummer to angir hvor mange elementer som skal plukkes, og om du utelater den plukkes bare et element. $array = Array("Ola", "Lars", "Per", "Nils"); // plukk ut et element print_r(array_rand($array)); echo "\n"; // plukk ut tre elementer print_r(array_rand($array, 3)); shuffle() shuffle() endrer rekkefølgen til verdien i arrayen, og fjerner alle indeksene. Den returnerer ingenting, men endrer på selve arrayen du sender inn. $array = Array("Ola", "Lars", "Per", "Nils"); shuffle($array); print_r($array); Køer og stakker Sortering er ikke det eneste man ønsker å gjøre med arrays. Ofte vil man behandle arrays som en kø eller som en stakk. Her er hvordan det gjøres.
42 42 Kapittel 4. Lister Array som kø Det finnes to funksjoner som lar deg behandle en array som en kø, nemlig array_push() og array_shift(). En kø er en liste hvor du legger til verdier i en ende og fjerner i den andre enden; altså et først inn, først ut-system. En analogi finner du i hvordan du stiller deg opp i kø på dagligvarebutikken. Selvsagt finnes det en egen terminologi for operasjoner på en kø; vi kaller det å "pushe" elementer inn i køen når vi legger til nye ting, og å "shifte" elementer fra køen når vi fjerner ting. array_push() legger til elementer bakerst i arrayet; Resultatet blir; $queue = Array("Ola", "Lars"); array_push($queue, "Per"); array_push($queue, "Nils"); print_r($queue); Array ( [0] => Ola [1] => Lars [2] => Per [3] => Nils ) Observante lesere legger gjerne merke til at array_push() gjør det samme som $queue[]. For å fjerne elementer framme i arrayen bruker vi array_shift(); $queue = Array("Ola", "Lars"); array_push($queue, "Per"); array_push($queue, "Nils"); $person = array_shift($queue); print_r($queue); print_r($person); Ut fra dette skriptet får vi følgende utskrift; Array ( [0] => Lars [1] => Per [2] => Nils ) Ola Du kan se at Ola har blitt fjernet fra køen, og blir gitt som resultat fra array_shift()- funksjonen. Arrays som stakk En stakk er en liste basert på først inn, sist ut-prinsippet. Tenk deg en stabel med tallerkner når du vasker opp. Du legger rene tallerkner på toppen av stabelen, mens personen som tørker også plukker fra toppen av den. Det betyr at den siste tallerkenen som blir lagt på, blir den første som blir tatt ut.
43 Kapittel 4. Lister 43 Stakker er svært mye brukt i lavnivåprogrammering på datamaskiner, men gjerne ikke like ofte i programmering på det nivået som PHP ligger på. Likevel har vi selvsagt tilgang på funksjoner for å behandle en array som en stakk; disse heter array_push() og array_pop(). I en kø snakket vi om å "pushe" verdier på slutten av køen, og å "shifte" verdier fra starten. I en stakk "pusher" vi verdier på stakken, og "popper" verdier fra stakken. Stakker brukes veldig ofte i systemer der man regelmessig veksler mellom å lese og skrive til listen, og eksempelet nedenfor viser dette. Det er gjerne noe mer avansert enn de vi har sett på tidligere. Det er ikke noe problem å modifisere skriptet til å bruke køer istedet for stakker, da trenger du bare å bytte ut array_shift() med array_pop(). $stack = Array(); // La oss starte med verdiene (0, 1, 2) på stakken array_push($stack, 0, 1, 2); $i = 2; // Fortsett til stakken er tom while (count($stack) > 0) // Halvparten av tiden legger vi til verdier // (Men pass samtidig på at vi ikke får for mange verdier) if (mt_rand(0, 20) < 10 && count($stack) < 10) $i++; array_push($stack, $i); // lag oversikt over stakken $str = implode(", ", $stack); echo "+ Pushet $i \tstakk: ($str)\n"; else $verdi = array_pop($stack); // lag oversikt over stakken $str = implode(", ", $stack); echo "- Shiftet $verdi \tstakk: ($str)\n"; count() i koden ovenfor brukes for å finne lengden på en hvilken som helst array. mt_rand() er en funksjon som gir tilbake et tilfeldig tall, i dette tilfellet mellom 0 og 20, og vi sjekker om dette tallet er mindre enn 10. implode()-funksjonen slår sammen en array til en string, og bruker en streng vi oppgir (i dette tilfellet komma og et mellomrom) mellom verdiene. Resultatet fra dette skriptet blir forskjellig hver gang, men under finner du typisk utdata fra skriptet. Linjer som begynner med pluss betyr at en verdi ble lagt til på stakken, linjer som begynner med minus indikerer at en verdi ble fjernet. På slutten av hver linje finner man også det nåværende innholdet på stakken. Som dere ser begynner vi med en stakk som inneholder (0, 1, 2) for at skriptet ikke skal avslutte med en gang.
44 44 Kapittel 4. Lister - Shiftet 2 Stakk: (0, 1) - Shiftet 1 Stakk: (0) + Pushet 3 Stakk: (0, 3) + Pushet 4 Stakk: (0, 3, 4) - Shiftet 4 Stakk: (0, 3) - Shiftet 3 Stakk: (0) + Pushet 5 Stakk: (0, 5) - Shiftet 5 Stakk: (0) - Shiftet 0 Stakk: () Oppsummering I dag har vi lært den enkleste måten å lagre sekvensiell data på, med arrays. Vi har gjennomgått hvordan de opprettes, hvordan man blar gjennom dem, hva man kan slå opp etter, hvordan de sorteres, de vanligste operasjonene man gjør på et array og til slutt hvordan de fungerer som køer og stakker. Det er flere ting vi ikke har gått gjennom her; multi-dimensjonale arrays er en av disse tingene. Ved å plassere arrays inne i arrays kan du lage relativt komplekse lagringsstrukturer som trær og matriser. Du skal i løpet av dette kapittelet ha fått nok kunnskap til å eksperimentere med dette selv. I neste kapittel skal vi gå gjennom funksjoner, hva de brukes til og hvordan man lager sine egne.
45 Kapittel 5. Funksjoner 45 Kapittel 5. Funksjoner Funksjoner lar deg bruke kodesnutter flere ganger. Funksjoner benyttes hovedsakelig for å unngå å skrive en bit kode om igjen flere ganger. Du kan gjerne tenke på funksjoner i PHP som matematiske funksjoner; du gir funksjonen en eller flere inn-verdier og den gir deg et resultat. Til forskjell fra vanlige matematiske funksjoner kan en PHP-funksjon også endre inn-verdiene, et spesialtilfelle vi skal snakke mer om senere. Dersom du har erfaring fra andre språk, kan det være at du har hørt om funksjoner tidligere, bare under et annet navn; metoder og prosedyrer er de mest vanlige betegnelsene på fenomenet. Hva er en funksjon? Selv om du kanskje ikke har vært klar over det, har vi brukt funksjoner tidligere i denne guiden. Kommandoene som er innebygd i PHP, slik som echo og print er funksjoner som språket tilbyr. Blant slike funksjoner finner man også matematiske funksjoner, slik som f.eks. utregning av sinus (sin) og cosinus (cos). Det interessante med funksjoner er at du også kan lage dine egne. En funksjon er en kodeblokk som på en måte er adskilt fra resten av koden din. I koden du skriver i funksjonen din har du kun tilgang på de variablene som er parametre til funksjonen. Dette blir svært abstrakt uten et kodeeksempel, så derfor kommer det et slikt nå. Med det du har lært til nå er gjerne følgende det du ville gjort dersom du ønsket å regne ut arealet og omkretsen for en sirkel for 3 forskjellige sirkler; $radius = 2; echo "Sirkel med radius $radius har areal ". ($radius * $radius * 3.14)." og omkrets ". (2 * 3.14 * $radius)."<br/>"; $radius = 4; echo "Sirkel med radius $radius har areal ". ($radius * $radius * 3.14)." og omkrets ". (2 * 3.14 * $radius)."<br/>"; $radius = 5; echo "Sirkel med radius $radius har areal ". ($radius * $radius * 3.14)." og omkrets ". (2 * 3.14 * $radius)."<br/>"; Som du ser blir dette fort ganske mye kode, selv for noe så enkelt som det å regne ut areal og omkrets for 3 tre sirkler. Ville det ikke vært kjekt om vi kunne skrevet noe så enkelt som SirkelInfo(3) for å få informasjonen om en sirkel med radius 3? Det kan vi fort ordne. function SirkelInfo($radius) echo "Sirkel med radius $radius har areal ". ($radius * $radius * 3.14)." og omkrets ". (2 * 3.14 * $radius)."<br/>"; SirkelInfo(2); SirkelInfo(4); SirkelInfo(5);
46 46 Kapittel 5. Funksjoner Som du ser har vi sluppet unna med å skrive vår lange setning en gang, i stedet for tre ganger som vi gjorde i det forrige skriptet. I tillegg til dette blir det enklere å oppdatere utregningen dersom det viser seg at pi ikke er akkurat lik 3,14, siden vi nå bare må oppdatere dette to plasser, i stedet for seks. Men det er mye her vi ikke har forklart. Først og fremst, for å definere en funksjon, bruker vi nøkkelordet function. Direkte etter dette ordet kommer navnet på funksjonen, som kan være omtrent hva du vil. Etterpå finner vi den såkalte parameterlisten i parenteser. Parameterlisten angir hvilke variabler som vil være tilgjengelig for koden inne i funksjonen. I vårt eksempel benytter vi oss bare av én parameter, $radius, som du kan se vi bruker flere ganger inne i funksjonen. Etter parameterlisten kommer selve funksjonen, avgrenset av de vanlige klammeparentesene. Vår funksjon består bare av den ene linjen som begynner med echo, siden vi kan gjøre alle våre utregninger der. Når du ønsker å kalle funksjonen du har laget, er du nødt til å skrive navnet dens etterfulgt av parenteser fylt med verdier for argumentene. Du kan gjerne sende inn variabler her, og variabelens verdi vil bli sendt til funksjonen. Vanlige feller Merk at kode som kjøres i en funksjon ikke normalt har tilgang på variablene som er definert utenfor funksjonen. For å unngå forvirring kan det være lurt å forsøke å unngå variabler med samme navn definert i en funksjon og utenfor en funksjon. Skriptet nedenfor har akkurat samme utdata som skriptet på forrige side. $radius = 8; function SirkelInfo($radius) echo "Sirkel med radius $radius har areal ". ($radius * $radius * 3.14)." og omkrets ". (2 * 3.14 * $radius)."<br/>"; SirkelInfo(2); $ostekake = 4; SirkelInfo($ostekake); SirkelInfo(5); Om du ønsker å få tilgang til variable definert på utsiden av funksjonen, kan du gjøre det ved å bruke nøkkelordet global. Legg merke til at PHP benytter definisjonen på $radius som finnes der funksjonen blir kjørt, ikke der funksjonen er deklarert. Resultatet av skriptet nedenfor blir derfor det samme som for skriptet over.
47 Kapittel 5. Funksjoner 47 function SirkelInfo() global $radius; // bruk $radius-variabel fra utenfor funksjonen echo "Sirkel med radius $radius har areal ". ($radius * $radius * 3.14)." og omkrets ". (2 * 3.14 * $radius)."<br/>"; $radius = 2; SirkelInfo(); $radius = 4; SirkelInfo(); $radius = 5; SirkelInfo(); Dersom du ønsker å definere en funksjon som tar flere parametre, kan du lett gjøre det ved å separere variabelnavnene med et komma. Den følgende funksjonen og bruk av den er et eksempel på dette. function Multipliser($faktor1, $faktor2) echo "$faktor1 * $faktor2 = ".($faktor1 * $faktor2); $verdi = 3; Multipliser(2, $verdi); Utskriften fra denne kjøringen av funksjonen blir "2 * 3 = 6". Returnere verdier Funksjonene du har sett til nå har kun skrevet ut tekst direkte til nettleseren. Som oftest benyttes funksjoner til å returnere en verdi, som du dermed kan jobbe videre med i koden din. Returnering av verdier gjøres ved hjelp av kommandoen return. Vi kan gå tilbake til vårt tidligere eksempel med sirkler. Dersom du ønsker å finne ut det totale arealet for flere sirkler vil det være upraktisk å benytte seg av SirkelInfo som vi definerte tidligere. Vi lager derfor en ny funksjon som returnerer arealet av en sirkel i stedet for å skrive det ut. function RegnUtSirkelAreal($radius) return $radius * $radius * ; $sum = 0; for ($i = 1; $i < 5; $i++) $sum += RegnUtSirkelAreal($i); echo "Sirklene med radius fra 1 til og med 5 har ". "et totalt areal på $sum<br/>"; Her bruker vi en kortform som du ikke har sett før. += betyr legg til den følgende verdien til variabelen, og er en kortere måte å skrive $sum = $sum + $noemer. I tillegg til denne nye kortformen, inneholder snutten over en svært vanlig feil når det gjelder for-løkker. Om du ikke finner feilen ved å lese gjennom koden, prøv å kjør den, endre litt på koden og finn feilen. Svaret kommer litt lenger ned (notis 1).
48 48 Kapittel 5. Funksjoner Her bruker vi return-kommandoen til å si hva funksjonens verdi er. Merk at vi kun kan kalle return en gang i hver funksjon, siden kode etter return ikke vil bli kjørt. Det betyr at vi kan endre vår funksjon ovenfor til å forhindre input av feil data; function RegnUtSirkelAreal($radius) if ($radius < 0) return 0; return $radius * $radius * ; Om du nå kaller denne funksjonen med en negativ radius, vil funksjonen alltid returnere 0 som areal, siden en sirkel ikke kan ha negativt areal. Dersom radiusen er mindre enn 0, vil return 0 bli kalt og linjen etterpå vil ikke kjøres. Husker du den vanlige feilen som vi nevnte over? Feilen består i at den utskrevne teksten sier at vi skal summere arealet av sirkler med radius fra 1 til og med 5, mens vi i for-løkken faktisk bare summerer arealet for sirkler fra 1 til og med 4. Det er fordi forløkken avslutter i det øyeblikket $i blir lik 5, ikke rett etterpå. Ved å endre sjekken fra < til <= vil det fungere. Prøv! NOTIS 1 Returnere flere verdier Det er nå det begynner å bli gøy. PHP benytter seg av lister veldig mye, så dersom du ønsker å returnere flere verdier kan du gjøre det ved å lage en liste og returnere den. Du kan også returnere objekter, som vi ennå ikke har fortalt deg om, men som vi skal behandle i et senere kapittel. Å lage en liste er svært enkelt, og vi kan endre vår tidligere SirkelInfo til å returnere en liste i stedet for å skrive ut teksten. function SirkelInfo($radius) $info['radius'] = $radius; $info['areal'] = $radius * $radius * 3.14; $info['omkrets'] = $radius * 2 * 3.14; return $info; $info = SirkelInfo(3); echo "En sirkel med radius 3 har en omkrets ". "på $info['omkrets'] og areal på $info['areal']<br/>"; Et annet alternativ er å endre som blir sendt inn som parametre. Dette er en måte som bør brukes med omhu, og fungerer best dersom du ønsker at endringene du gjør i funksjonen også skal gjelde for variabelen som du bruker når du kaller funksjonen. Her er det vanskelig å komme med et svært godt eksempel, så vi bruker noe så primitivt som en funksjon som legger til en til en verdi.
49 Kapittel 5. Funksjoner 49 function LeggTilEn($verdi) $verdi++; $ost = 4; LeggTilEn($ost); echo $ost; Intuitivt vil du kanskje si at dette skriptet skriver ut tallet 5, men det stemmer ikke. Vi har ikke på noen måte fortalt PHP at endringer gjort til $verdi også skal gjelde for variabelen den representerer. Stilen brukt ovenfor kalles call by value, som indikerer at det kun er verdien som blir sendt til funksjonen. Om vi ønsker at endringene også skal gjelde for den nye verdien, kan vi gjøre følgende; function LeggTilEn(&$verdi) $verdi++; $ost = 4; LeggTilEn($ost); echo $ost; // Skriver ut 5 Her er det et-tegnet (&) som gjør at funksjonen kan endre variabelen som blir sendt inn til funksjonen. I stedet for at funksjonen får sin egen kopi av variabelen $ost, som er det som skjer til vanlig, får funksjonen nå en referanse til den originale variabelen. Når variabelen endres i funksjonen, vil endringen derfor også skje med den eksterne variabelen. På engelsk kalles dette pass by reference (når du sender inn en referanse), i motsetning til pass by value, som er standard. Oppsummering I dag har vi snakket om funksjoner, et svært viktig verktøy for å dele opp koden din og å la deg slippe å skrive den samme koden flere ganger. Å kunne se hvilken kode som er gjenbrukbar er ofte en egenskap som tar noe tid å lære seg, og du lærer det best med erfaring. Vi har gått gjennom hva en funksjon er, og hvordan den defineres. Deretter dekket vi noen vanlige feller å gå i når man lager funksjoner, og hvordan man kan omgå dem. Så gikk vi gjennom hvordan man returnerer verdier, og til slutt hvordan man kan returnere mer enn en verdi fra en funksjon. Neste gang skal vi snakke om hvordan man kan ta imot data fra en nettside, og hva man må passe på underveis. Å bruke data som brukeren gir oss er en svært viktig del av det å lage dynamiske websider.
50 50 Kapittel 6. Ta imot data fra brukeren Kapittel 6. Ta imot data fra brukeren For å lage dynamiske websider i PHP er man nødt til å ta imot og behandle data fra brukeren. Bare slik kan man tilpasse nettsiden til brukeren. I dag lærer du hvordan du kan ta imot data fra besøkende, på samme måte som vårt forum fungerer. Vi er nå klar med det sjette kapittelet i vår gjennomgang av PHP og MySQL. Vi har ennå ikke kommet frem til den delen som skal handle om MySQL, men vi nærmer oss med stormskritt. I dag er temaet hvordan du enklest mulig kan ta imot og behandle data fra leseren av nettsiden din. Det er først når man bruker data fra brukeren at man virkelig lager dynamiske og interaktive nettsider som det kan være interessant for leseren å bruke tid på. Basiskunnskaper For å gi data til våre PHP-skript, er vi nødt til å benytte oss av HTML og HTTP sine metoder for innsending av data til serveren. Det gir oss to metoder å gi data til en nettside på. Den ene kalles GET-syntaks, og variabler sendt ved denne syntaksen kan du lese fra adresselinjen i nettleseren. Om du besøker vår prisguide og ser på tastatur-kategorien 14, ser du at det er en variabel i adresselinjen, cat_id, som er satt til 33. Det betyr at du kan linke til skript ved å bruke GETsyntaks. Den andre metoden kalles POST-syntaks, og er ikke synlig i adresselinjen. Denne syntaksen brukes som oftest når du benytter deg av HTML-skjemaer for å sende inn data, og den må brukes dersom du skal la brukeren laste opp filer. I all hovedsak kommer vi til å konsentrere oss om GET-syntaksen i dag. Et HTML-skjema som lar brukeren skrive inn fornavnet og etternavnet sitt ser slik ut; <form method="post" action="velkommen.php"> <p>fornavn: <input type="text" name="fornavn" /></p> <p>etternavn: <input type="text" name="etternavn" /></p> <p><input type="submit" value="send inn" /></p> </form> Siden vi antar at du kan grunnleggende HTML, skal vi ikke gå spesielt inn på HTML-koden her, og har derfor uthevet de viktige punktene i koden ovenfor. Dette HTML-skjemaet er bare et utdrag av en full HTML-side, og er derfor ikke gyldig HTML. På første linjen angir den at vi skal benytte oss av POST-syntaks, og at skjemaet skal sendes til filen velkommen.php. Neste linje gir mulighet for å skrive inn fornavn, og det angir navnet på feltet; fornavn. Linjen etterpå gjør det samme for etternavn, og til slutt har vi en "Send inn"- knapp. For å ta imot dataene må vi nå lage en PHP-fil ved navnet velkommen.php. I første omgang skal vi bare skrive ut strengen "Velkommen,!", slik at vi vet at det virker. Her er koden; 14
51 Kapittel 6. Ta imot data fra brukeren 51 if ($_REQUEST['fornavn'] && $_REQUEST['etternavn']) $fornavn = htmlentities(strip_tags( stripslashes($_request['fornavn']))); $etternavn = htmlentities(strip_tags( stripslashes($_request['etternavn']))); echo "Velkommen, $fornavn $etternavn!"; else echo "Du har ikke komt til denne siden på rett måte."; Å få tak i det som blir sendt til PHP-skriptet gjør vi svært enkelt gjennom $_REQUEST. Dette er en superglobal variabel (superglobal betyr at du får tilgang til den fra hvor som helst i et PHP-skript uten å måtte bruke nøkkelordet global). Variabelen inneholder en array, som er indeksert med navnene på feltene som blir sendt inn. Husk at feltnavnene er versalsensitive, som betyr at det blir gjort forskjell på store og små bokstaver. Først sjekker vi om de to påkrevde variablene er satt. Siden en tom string blir gjort om til FALSE når man bruker den i en if-setning, slipper vi å bruke funksjoner som empty() for å sjekke om disse variablene er satt. Om de ikke er satt, skriver vi bare ut en feilmelding. Før vi sender data tilbake til brukeren, ser du at vi bruker tre forskjellige funksjoner på dataene. Dette har med sikkerhet å gjøre, og vi går inn i detaljene for dette på neste side. Til slutt skriver vi ut en velkomsttekst til brukeren. Sikkerhet Mantraet til enhver programmerer må være "aldri stol på brukeren." Dette gjelder spesielt webapplikasjoner, som på grunn av at de alltid er tilgjengelig fra hele verden er spesielt sårbare for sikkerhetshull. Et angrep mot din webapplikasjon kan ta den ned fra nettet, bytte den ut med andre nettsider, eller i verste fall bli benyttet i phishing-svindler. De følgende funksjonene kan hjelpe deg godt på vei, men er ikke det eneste du må tenke på. stripslashes() Dette er strengt tatt ingen sikkerhetsfunksjon, men den blir brukt for å forhindre at data sendt fra brukeren blir forandret i oversendelsen. Data som blir oversendt fra brukeren som inneholder tegn som ' (enkelt anførselstegn) eller " (dobbelt anførselstegn) vil få en skråstrek lagt til foran hvert av disse tegnene. stripslashes() fjerner disse igjen. Det er vanskelig å demonstrere dette på en god måte fra et enkelt PHP-skript, siden denne endringen bare oppstår når man får data fra brukeren eller når man bruker addslashes(). Her er i alle fall et forsøk på å vise hva som skjer. $tekst1 og $tekst2 representerer data slik man får det inn fra en bruker. $tekst1 = addslashes("it was James' toy. He told John \"No!\""); $tekst2 = addslashes('it was James\' toy. He told John "No!"'); echo $tekst1."\n"; echo $tekst2."\n"; echo stripslashes($tekst1)."\n"; echo stripslashes($tekst2);
52 52 Kapittel 6. Ta imot data fra brukeren Utdata fra dette skriptet blir It was James\' toy. He told John \"No!\" It was James\' toy. He told John \"No!\" It was James' toy. He told John "No!" It was James' toy. He told John "No!" Legg merke til at de to første linjene er helt like (dvs. at $tekst1 og $tekst2 er to måter å skrive samme strengen på). strip_tags() strip_tags() brukes for å fjerne HTML-tagger fra en streng. Det er viktig av mange grunner, spesielt siden data fra en bruker kan inneholde blant annet JavaScript. JavaScript kan benyttes til å sende brukeren til en annen nettside, så folk tror de besøker din nettside (fordi adressen er jo helt lik som adressen til din side), men så sender noe JavaScript-kode dem videre. $tekst[] = "<b>vegard</b> er <em>kul!</em>"; // for å forhindre at vi faktisk blir videresendt, // er det en feil i JavaScriptet under $tekst[] = "<script type=\"text/javascript\">windows.". "location = \" $tekst[] = "vanlig tekst"; foreach ($tekst as $t) echo "\n". $t. " -> ". strip_tags($t); Legg merke til at vi var nødt til å legge inn en skrivefeil i JavaScript-koden for at den ikke skulle videresende oss til Hardware.no med en gang vi lastet siden. Om vi ser på kildekoden som dette PHP-skriptet produserer, så ser det omtrent slik ut (vi la til to linjeskift for leselighetens skyld); <b>vegard</b> er <em>kul!</em> -> Vegard er kul! <script type="text/javascript">windows.location = " -> windows.location = " vanlig tekst -> vanlig tekst Ondsinnet angrepskode som JavaScriptet ble nå nøytralisert, og brukere som tror de er smarte og registrerer brukernavn med HTML-tagger får et brukernavn som ikke er like kult som de trodde! htmlentities() htmlentities() konverterer tegn som kan føre til trøbbel i HTML, slik som < og de særnorske bokstavene til HTML-sekvenser som <& og å (å). Det er viktig for å unngå trøbbel med tegnsett, siden nettsiden kan vises i et annet tegnsett enn brukeren sender inn, og særnorske tegn har en tendens til å være de første som lider av det. Denne funksjonen slår også ut evt. HTML-kode i input-dataene, men på en litt annen måte enn strip_tags(). Forskjellen er at selve HTML-koden blir synlig når du bruker htmlentities(), mens den blir fjernet med strip_tags(). Her er et lite eksempel på bruk av htmlentities() (omtrent det samme som over);
53 Kapittel 6. Ta imot data fra brukeren 53 $tekst[] = "<b>vegard</b> er <em>kul!</em>"; // for å forhindre at vi faktisk blir videresendt, // er det en feil i JavaScriptet under $tekst[] = "<script type=\"text/javascript\">windows.". "location = \" $tekst[] = "vanlig tekst"; foreach ($tekst as $t) echo "\n". $t. " -> ". htmlentities($t); Resultatet blir som følger. Det er gjerne litt vanskelig å lese, og dette viser nøyaktig utskrift fra skriptet. Om du ser på resultatet i en nettleser blir det annerledes. <b>vegard</b> er <em>kul!</em> -> <b>vegard</b> er <em>kul!</em> <script type="text/javascript">windows.location = " -> <script type="text/javascript">windows.location = " vanlig tekst -> vanlig tekst Sammenhengen Vi bruker stripslashes(); først for å fjerne eventuelle artefakter som har oppstått under overføringen fra brukeren. Deretter bruker vi strip_tags() for å fjerne eventuell ondsinnet HTML-kode fra brukerens side. Til slutt bruker vi htmlentities() for å gjøre om tegn som ikke finnes i ASCII til HTML-koder som tilsvarer det samme. Dette er stort sett ting du bruker når det er snakk om frie tekst-strenger. Om det er snakk om ting som e-postadresser er det verdt bryet å definere nøyaktig hva som er en gyldig e- postadresse. Til det bruker vi gjerne såkalte regular expressions (regulære uttrykk, ofte forkortet regexp). Det skal vi ta for oss på neste side. Regulære uttrykk Regulære uttrykk er et svært bredt emne, og det kan ta flere år å virkelig mestre dem. Man bruker regulære uttrykk til å finne strenger som passer til et gitt mønster. Det regulære uttrykket oppgir dette mønsteret, og er rett og slett en tekst-streng med såkalte meta-tegn som kan matche ting. PHP har støtte for to forskjellige typer regulære uttrykk. De første, de såkalte PCRE/Perlkompatible funksjonene 15 er de vi kommer til å bruker her i denne guiden, fordi dem som er mest utbredt i bruk, og fordi de er kraftigere. De andre regulære uttrykkene i PHP følger utvidet POSIX-standard 16, og er enklere, men støtter ikke så veldig avanserte teknikker. Grunnleggende Alle de PERL-kompatible funksjonene begynner med preg_. I dag skal vi konsentrere oss om preg_match(), som sjekker om den oppgitte strengen har minst et treff til felles med det regulære uttrykket. De andre funksjonene har nøyaktig samme syntaks for det regulære uttrykket, så når du har lært det grunnleggende i dag, kan du eksperimentere med disse
54 54 Kapittel 6. Ta imot data fra brukeren Vi begynner med noe så enkelt som å validere et telefonnummer. Det er svært enkelt å bruke preg_match() til å godkjenne et norsk, 8-sifret telefonnummer; $nummer[] = " "; $nummer[] = " "; $nummer[] = " "; $nummer[] = " "; // matcher strenger som kun inneholder et 8-sifret tall $regex = "/^\d8$/"; foreach ($nummer as $n) echo $n.": ".preg_match($regex, $n)."<br/>\n"; Vi tester mot fire forskjellige telefonnummer, alle gyldige, men noen er ikke norske. Vårt første naive forsøk matcher de norske nummerene veldig greit, men sliter med nummer som inneholder mellomrom eller et internasjonalt prefix : : : : 0 Uttrykket vi bruker her; /^\d8$/, kan virke skremmende i begynnelsen. Uttrykket begynner og avsluttes med en skråstrek, og dette er alltid med i alle Perl-kompatible regulære uttrykk. \d står for desimal-tall, dvs. alle siffer fra 0 til 9. I klammeparenteser bakom finner du tallet 8, som oppgir hvor mange tall det må være. Hatten i begynnelsen indikerer betyr at "det neste tegnet må være helt på begynnelsen av strengen vi sammenligner mot", og dollartegnet på slutten betyr at "forrige tegn må være helt på slutten av strengen vi sammenligner med". Effekten blir at dette uttrykket kun godkjenner en streng som kun består av 8 siffer i rekkefølge. Hva med mellomrommene? Hva om vi skal utvide eksempelet ovenfor til å også godkjenne mellomrom? Den første tanken vil være å se på mønsteret ovenfor, og tenke at norske telefonnummer gjerne skrives i grupper på to og to siffer. Da får man følgende regulære uttrykk; $regex = "/^(\d2?)3\d2$/"; Dette uttrykket godkjenner tre av numrene i eksempelet ovenfor. Dette regulære uttrykket sier at et norsk telefonummer består av grupper på to og to tall, evt. etterfulgt av et mellomrom. Spørsmålstegnet angir at tegnet foran det kan forekomme en gang eller ikke i det hele tatt. Grupper på to etterfulgt av et mellomrom kan skje tre ganger, og til slutt kommer det en gruppe på to tall. Dette regulære uttrykket godkjenner derimot ikke " ", som også er en vanlig måte å skrive norske nummer. Hva om vi fjernet mellomrommene helt? Det er svært enkelt å gjøre med regulære uttrykk;
55 Kapittel 6. Ta imot data fra brukeren 55 $nummer[] = " "; $nummer[] = " "; $nummer[] = " "; $nummer[] = " "; // matcher strenger som kun inneholder et 8-sifret tall $regexfjern = "/\s*/"; $regexmatch = "/^\d8$/"; foreach ($nummer as $n) $t = preg_replace($regexfjern, '', $n); echo $n." (redusert til $t): ".preg_match($regexmatch, $t)."<br/>\n" ; Vi bruker her funksjonen preg_replace() for å fjerne mellomrom (\s er et metategn i regulære uttrykk som betyr "alle typer mellomrom, slik som tab, enter og space"). Deretter bruker vi vår originale sammenligningsmetode som ser etter åtte sammenhengende tall. Nå godkjenner vi alle norske siffer. Slik ser forresten resultatet ut; (redusert til ): (redusert til ): (redusert til ): (redusert til ): 1 Internasjonale nummer Kanskje du ikke trenger å gjenkjenne internasjonale nummer, men vi forsøker å lage en slik regex likevel. Utenlandsnummer begynner med enten et plusstegn eller to nuller, etterfulgt av en landskode fra et til tre siffer. Deretter antar vi at alle land har telefonnummer som er mellom fem og tolv siffer langt. Vi legger også til noen ekstra telefonnummer å teste mot, i tillegg til et som ikke skal bli godkjent. $nummer[] = " "; $nummer[] = " "; $nummer[] = " "; $nummer[] = " "; $nummer[] = " "; $nummer[] = " "; $nummer[] = "Vegard"; // matcher strenger som kun inneholder et 8-sifret tall $regexfjern = "/\s*/"; $regexmatch = "/^((\+ 00)(\d1,3))?\d5,12$/"; foreach ($nummer as $n) $t = preg_replace($regexfjern, '', $n); echo $n." (redusert til $t): ".preg_match($regexmatch, $t)."<br/>\n" ; Vi fjerner fortsatt mellomrom med det samme regulære uttrykket som tidligere, men har nå lagt inn et lengre og mer komplisert uttrykk i tillegg. Her er nedbrytingen;
56 56 Kapittel 6. Ta imot data fra brukeren ((\+ 00)(\d1,3))? sier at vi kan begynne med en sekvens som består av + eller 00, etterfulgt av et til tre siffer. \d5,12 sier at her må det være mellom fem og tolv tall i rekkefølge. Resultatet fra skriptet blir; (redusert til ): (redusert til ): (redusert til ): (redusert til ): (redusert til ): (redusert til ): 1 Vegard (redusert til Vegard): 0 Her er en oppgave til deg. Utvid det regulære uttrykket over til å også godkjenne telefonnummer på formen "(47) ", som er en mye brukt måte å oppgi internasjonale nummer på i utlandet. Å lage tilsvarende valideringer for e-post-adresser og URL-er er fullt mulig, om enn noe mer avansert. Du må også være svært forsiktig når du bruker regulære uttrykk for å avvise input fra brukeren, og gjør deg selv helt sikker på at ditt regulære uttrykk godkjenner alt som kan være gyldig input. Validere e-post Den følgende funksjonen er en relativt robust måte å validere e-postadresser på, og har med alle de godkjente bokstavene i brukernavn og domenenavn. Den er tatt direkte fra en kommentar 17 på PHP.net, som nok en gang viser at det lønner seg å lese PHP-manualen. Men merk også at denne funksjonen ikke godkjenner e-postadresser med nasjonale bokstaver, slik som de særnorske bokstavene, og at den derfor ikke godkjenner e-postadresser på IDN-domener. <? function is_ ($addr) $p = '/^[a-z0-9!#$%&*+-=?^_` ~]+'; $p.= '(\.[a-z0-9!#$%&*+-=?^_` ~]+)*'; $p.= '@([-a-z0-9]+\.)+([a-z]2,3'; $p.= ' info arpa aero coop name museum)$/ix'; return preg_match($p, $addr); Feilmeldinger Det er viktig å gi brukeren tilbakemelding dersom det oppstår feil med valideringen av data som har blitt innsendt. Den gjerne enkleste måten å gjøre dette på, er ved bruke funksjonen die(), og la skriptet avslutte med en feilmelding. Brukeren må så bruke tilbake-knappen i nettleseren for å rette opp feilene. En mer behagelig måte, for brukeren i alle fall, er å sette opp igjen det originale skjemaet med de korrekte verdiene ferdig innfylt. Felt som brukeren har glemt lar du stå tomme, og marker dem gjerne med en bakgrunnsfarge eller en godt synlig stjerne bak feltet. En enkel måte å gjøre dette på, er ved å sørge for at utfyllingsskjemaet og logikk-koden ligger i samme PHP-fil. Her er et enkelt eksempel; 17
57 Kapittel 6. Ta imot data fra brukeren 57 $fornavn = ""; $etternavn = ""; if ($_REQUEST['fornavn'] && $_REQUEST['etternavn']) $fornavn = htmlentities(strip_tags( stripslashes($_request['fornavn']))); $etternavn = htmlentities(strip_tags( stripslashes($_request['etternavn']))); $gyldig = ($fornavn == 'Vegard') && ($etternavn == 'Larsen'); if (!$gyldig) <form method="post" action="6-12.php"> <p>fornavn: <input type="text" name="fornavn" value=" echo $fornavn; " /> </p> if ($fornavn!= 'Vegard' && $fornavn!= '') echo "<p style=\"color: red;\"><b>du får kun logge ". "inn om du heter Vegard til fornavn</b></p>"; <p>etternavn: <input type="text" name="etternavn" value=" echo $etternavn; "/> </p> if ($etternavn!= 'Larsen' && $etternavn!= '') echo "<p style=\"color: red;\"><b>du får kun logge ". "inn om du heter Larsen til etternavn</b></p>"; <p><input type="submit" value="send inn" /></p> </form> else echo "Velkommen tilbake, Vegard!"; Vi viser kun feilmeldingene dersom brukeren allerede har forsøkt å logge inn en gang tidligere. Koden ovenfor er også et godt eksempel på at det er fullt mulig å blande PHP-kode og HTMLkode, men man ser også hvor fort det blir rotete. På et senere tidspunkt i denne artikkelserien kommer vi til å gå gjennom såkalte templatesystemer, som lar deg skrive mye ryddigere kode. Ta imot arrays Ved å definere feltnavn i et skjema som inneholder klammeparenteser, kan du bruke input-felt som direkte blir omgjort til en array i PHP-kode. Det er veldig enkelt;
58 58 Kapittel 6. Ta imot data fra brukeren <form method="post" action="6-13.php"> $array = $_REQUEST['array']; for ($nr = 1; $nr < 10; $nr++) <p>felt echo $nr; : <input type="text" name="array[ echo $nr; ]" value=" if ($array[$nr]) echo htmlentities(strip_tags(stripslashes($array[$nr]))); " /> </p> <p><input type="submit" value="send inn" /></p> </form> Dette skriptet skriver ut ni felt, med name-attributtet satt til array[1], array[2], osv. PHPskriptet kan da hente ut disse verdiene gjennom $_REQUEST['array'], og bruke denne som en array. Dersom det finnes en verdi for feltet som blir skrevet ut, setter vi den direkte inn. En lettere endret versjon av dette skriptet viser at det er mulig å opprette arrays uten å oppgi indeksen; <form method="post" action="6-13.php"> $array = $_REQUEST['array']; for ($nr = 0; $nr < 10; $nr++) <p>felt echo $nr; : <input type="text" name="array[]" value=" if (isset($array[$nr])) echo htmlentities(strip_tags(stripslashes($array[$nr]))); " /> </p> <p><input type="submit" value="send inn" /></p> </form> Her er name-attributtet satt til array[] for alle input-feltene. Da får vi en array indeksert fra 0 og oppover, og vi har defor endret loop-variabelen til å gå fra 0 i stedet for fra 1. POST, GET og REQUEST I begynnelsen av dette kapittelet nevnte vi at det finnes to måter å sende data til et PHP-skript på, POST og GET. Frem til nå har vi brukt $_REQUEST-variabelen for å hente ut data som brukeren har sendt inn. Denne variabelen er en kombinasjon av dataene som er sendt inn via POST og GET, i tillegg til data fra såkalte cookies (vi har ikke lært om dem ennå, og vi kommer tilbake til det senere). Rekkefølgen dette skjer i, er at først blir GET-variabler satt i $_REQUEST, deretter POST-variabler og til slutt cookie-variabler. Det betyr at dersom du har POST- og GET-variabler ved samme navn, vil kun POST-variabelen bli lagret i $_REQUEST.
59 Kapittel 6. Ta imot data fra brukeren 59 Du kan løse dette ved å benytte deg av variabler tilsvarende $_REQUEST for de ulike typene. GETdata finner du også i variabelen $_GET, POST-data i variabelen $_POST, og cookie-data i variabelen $_COOKIE. Ellers fungerer disse variablene på nøyaktig samme måte som $_REQUEST GET-adresser Vi nevnte i begynnelsen at når du bruker GET-syntaks for å sende variabler, så kan man se variablene direkte i adressen til siden. Om du surfer rundt på for 18 umet, vil du se at adressen til PHP-forumet er Biten som sier?showforum=30 er en variabel satt ved hjelp av GET-syntaks. Om vi forsøker å svare på en tråd, får vi en adresse på denne formen; Her er det fire variabler som blir satt; act, CODE, f og t, henholdsvis med verdiene Post, 02, 30 og Du kan se at variabel-rekken begynner med et spørsmålstegn, og videre utover separeres variabler med et-tegn. Det kjekke med å bruke GET-syntaks i stedet for POST-syntaks, er at vi kan lage vanlige lenker med slike variabler satt. Det er ikke mulig med POST-syntaks, og derfor blir GET-syntaksen også oftere brukt enn hva vi kanskje demonstrerer i denne artikkelen. Dersom du skal sette inn tekst i en slik adresse ved hjelp av PHP, kan du bruke funksjonen urlencode(), men den gjør det svært vanskelig å lese adressen for et menneske. Dersom det er en sjanse for at teksten du skal bruke som variabel inneholder et-tegn eller andre tegn med spesiell betydning, bør du bruke htmlentities() på den før du skriver den i en URL. Ta imot filer PHP kan også ta imot opplastede filer fra brukere. Da trenger du et skjema med en spesiell input-tag med type satt til file. Filene som blir lastet opp, er tilgjengelig gjennom $_FILESvariabelen, men før du får tatt den i bruk er det noen detaljer vi må igjennom. Først og fremst må skjemaer som skal motta annet enn tekstfiler få satt attributtet enctype til multipart/form-data. Du er også nødt til å bruke POST-metoden for å laste opp filer. Som standard er PHP satt til å maksimum tillate opplasting av filer på 2 MB. Det kan være en begrensning som det kan være verdt å endre om du føler for det. <form enctype="multipart/form-data" method="post" action="6-15.php"> Bilde (jpeg, jpg, png, gif): <input type="file" name="bilde" /> <input type="submit" value="last opp" /> </form> Dette er skjemaet du trenger for å tillate opplasting av en fil. Dette skjemaet blir seende slik ut i en nettleser (skjemaet nedenfor virker ikke, bare så du vet det); Bilde (jpeg, jpg, png, gif): Last opp Gitt at dette skjemaet har filnavnet 6-14.php, kan vi lagre følgende kode som 6-15.php og ha fungerende filopplasting. 18
60 60 Kapittel 6. Ta imot data fra brukeren // kast brukeren tilbake om han ikke har lastet opp bilde if (empty($_files['bilde'])) header('location: 6-14.php'); $bilde = $_FILES['bilde']; // sjekk filendelsen på originalfilnavnet $pathinfo = pathinfo($bilde['name']); $ext = strtolower($pathinfo['extension']); // sjekk at filendelsen er gyldig if (in_array($ext, Array('jpeg', 'jpg', 'gif', 'png'))) // lag et unikt navn for bildet $nyttnavn = './bilder/'. $pathinfo['basename']. '-'. mt_rand(0, ). '.'. $ext; // flytt den opplastede filen til ny katalog move_uploaded_file($bilde['tmp_name'], $nyttnavn); // vis bildet echo '<img src="'.$nyttnavn.'" alt="bilde" />'; else die('ikke en JPEG, GIF eller PNG-fil!'); // la brukeren laste opp et bilde til include('6-14.php'); Vi passer på å sjekke at brukeren faktisk har lastet opp en fil, og at den har rett filendelse. Dette er ikke en helt trygg metode, siden brukeren bare kan gi filen han laster opp feil filendelse, og på den måten lett laste opp en.exe-fil. Dette kan du forbedre ved å sjekke MIME-typen i tillegg (den finnes i $_FILES['bilde']['type'], men også denne kan forfalskes). Den beste måten å kontrollere dette på, er å bruke et faktisk bildebibliotek til å åpne bildene og sjekke at det er et bilde. Slik ser det ut når vi har lastet opp et av ingressbildene til denne artikkelserien. Vi sørger også for å generere et noenlunde unikt filnavn (sannsynligheten for at vi skal få to like filnavn er svært liten). For å få skriptet til å fungere, må brukeren som web-serveren kjører under ha skriverettigheter til bilder-mappen, slik at man får flyttet bildet til denne katalogen. Begrens filstørrelsen Det finnes to måter du kan begrense filstørrelsen på. Du kan enten sjekke $_FILES['bilde']['size']-variabelen, som oppgir størrelsen på bildet i bytes. Denne kan du bruke til å avvise bildet på. Du kan også legge inn et spesielt felt i HTML-koden som du sender til brukeren, som de aller fleste nettlesere bruker til å forhindre brukeren i å laste opp for store filer. Du kan derimot ikke kun stole på denne metoden, fordi brukeren kan benytte seg av en nettleser som ikke har støtte for dette, og dermed få lastet opp en større fil. Slik ser iallfall skjemaet ut med en begrensing på 50 kb;
61 Kapittel 6. Ta imot data fra brukeren 61 <form enctype="multipart/form-data" method="post" action="6-15.php"> <input type="hidden" name="max_file_size" value="50000" /> Bilde (jpeg, jpg, png, gif): <input type="file" name="bilde" /> <input type="submit" value="last opp" /> </form> Om du vil laste opp større filer enn PHP-begrensningen på 2 MB, må du gjerne modifisere php.ini, men om du kjøper webhotell hos noen har du gjerne ikke tilgang til dette. Endringene krever at webserveren startes på nytt, så slike endringer bør du gjøre så sjelden som mulig. Oppsummering I dag har vi dekket masse. Vi har gått igjennom hvordan du kan ta imot data fra brukeren ved hjelp av POST og GET. Vi har sett på hvilke sikringstiltak du må ta når du skal behandle data du har mottatt fra brukeren. Vi har lært deg grunnleggende regulære uttrykk, som lar deg bli sikker på at dataene du har fått tilsvarer det du forventet å få. Hardware-nettverkets publiseringssystem, ne:o, benytter seg svært mye av skjemaer, som du nå er en ekspert på. Vi har gitt deg noen tips om hvordan du bør gi feilmelding til brukerne av nettsiden din når de fyller inn data på feil måte (for det kommer de til å gjøre). Vi har vist deg hvordan du kan ta imot arrays som brukeren sender inn, hva forskjellen på POST, GET og REQUEST er, og til slutt hvordan du kan ta imot opplastede filer. I neste kapittel skal vi gå løs på såkalt objekt-orientert programmering (OOP). Vi har til nå klart å unngå bruk av objekter i det hele tatt, og OOP kommer til å være en helt ny måte å tenke programmering på.
62 62 Kapittel 7. Objekt-orientering Kapittel 7. Objekt-orientering I dette kapittelet skal vi dekke objekt-orientering, som er en metode for å sette data og oppførsel i sammenheng. Vi er nå klar med det syvende kapittelet i vår gjennomgang av PHP og MySQL. Vi har ennå ikke kommet frem til den delen som skal handle om MySQL, men vi nærmer oss med stormskritt. I dag er temaet hvordan man kan lage objekter, som lar deg samordne data med en gitt type oppførsel. Forord I dette kapittelet har vi valgt å benytte oss av det nye objekt-orienterte systemet som ble innført med PHP5. PHP5 har vært tilgjengelig siden juli 2004, og likevel er det svært mange webhotell som enda ikke har tatt det i bruk. Det er likevel tilgjengelig i blant annet XAMPP-pakken, som vi anbefalte i det første kapittelet av denne artikkelserien. Det er såpass mange endringer mellom PHP4 og PHP5 når det kommer til objekt-orientert programmering, at dersom du ikke har tilgang til en PHP5-basert installasjon, vil dette kapittelet dessverre være stort sett unyttig for deg når det gjelder programmeringsbiten. Likevel presenterer vi også mye teori i dette kapittelet, og den vil ikke være helt bortkastet, selv om noe av det ikke er mulig å bruke i PHP4. Klasser og objekter Hva er så objekt-orientering? Når man programmerer jobber man i all hovedsak med to ting; data og oppførsel. Til nå har vi kalt dataene våre vært lagt i variabler, mens oppførselen finner vi i funksjoner, og de har dermed vært separate. Objekt-orientering lar deg gruppere data og oppførsel i klasser. Klasser og objekter er de to hovedbegrepene man må innom når man snakker om objektorientert programmering. En klasse beskriver hvordan et objekt ser ut, hvilke funksjoner og variable det har. En klasse kan på den måten sammenlignes med konstruksjonstegningen over et hus; den beskriver hvordan man skal bygge huset og hva det skal inneholde, men konstruksjonstegningen er ikke selve huset. Du kan bygge flere hus (objekter) fra en tegning (klasse). Objekt-orientering er på denne måten en enkel måte å definere hvordan data og oppførsel henger sammen. Tenk deg en klasse som heter Hund, som sier at objekter laget fra denne klassen har fire bein, en hale, et navn, og metodene laglyd() og logremedhale(). Klassen definerer da bare det grunnleggende om hvordan en hund oppfører seg, men er nettopp bare det, en abstrakt beskrivelse. Vi kan definere vår abstrakte hund ved hjelp av PHP-nøkkelordet class. Her er hvordan undertegnede ser for seg en hund;
63 Kapittel 7. Objekt-orientering 63 class Hund // standardutstyr på en hund private $bein = 4; private $hale = TRUE; // navnet er individuelt private $navn; // lag en ny hund med et gitt navn public function construct($navn) $this->navn = $navn; // lager en typisk hundelyd public function laglyd() echo $this->navn." sier: Voff!<br/>"; // lar hunden vår logre med halen public function logremedhale() echo $this->navn." logrer med halen!<br/>"; Merk at om du kjører dette PHP-skriptet, vil du ikke få noe utdata i det hele tatt. Det er fordi dette bare er en definisjon, og vi oppretter på ingen tidspunkt et Hund-objekt, men vi sier bare noe om hvordan et Hund-objekt ville sett ut dersom vi hadde produsert en Hund. class-nøkkelordet etterfølges av navnet på klassen vi definerer, og alt som er innenfor de påfølgende klammeparentesene er en del av klassedefinisjonen. Medlemsvariabler, slik som $bein, $hale og $navn i eksempelet, må skrives med et spesielt nøkkelord som angir synlighet foran. Her har alle medlemsvariablene synligheten private, noe vi skal komme nærmere inn på senere. Funksjoner deklareres på samme måte som tidligere, bare med unntaket at du må ha private, protected eller public foran nøkkelordet function. En av funksjonene i eksempelet over er spesiell, construct(). Denne kalles en konstruktor, og er den som blir kjørt når du instansierer (lager) et Hund-objekt. For å lage et Hund-objekt, må du gi hunden ditt et navn. $this->navn gir deg tilgang til hundens interne navn-variabel, mens $navn kun peker til parameteret til funksjonen construct(). $this er en spesiell variabel som gir deg det objektet som du jobber på. Det er gjennom denne variabelen du får tilgang til funksjonalitet som finnes andre plasser i objektet (om det måtte være variabler eller funksjoner).
64 64 Kapittel 7. Objekt-orientering Lage objekter Å opprette objekter når man har klassedefinisjonen er svært enkelt. Om du skriver følgende kode nederst i skriptet ovenfor, vil du få skrevet ut to linjer når du kjører det. $fido = new Hund("Fido"); $fido->laglyd(); $fido->logremedhale(); Det er den første linjen som oppretter objektet, og du er nødt til å gi inn det antall parametre som konstruktoren krever. Nøkkelordet er new, og du må huske å tilordne objektet ditt en variabel. De to neste linjene kaller funksjoner på objektet, først laglyd() og deretter logremedhale(). Legg merke til syntaksen som blir brukt her, $fido->laglyd() sier at i objektet som $fido inneholder, kall metoden laglyd(). Om du har en medlemsvariabel med synlighet public, kan du få tilgang til den med $fido->variabel, den eneste forskjellen er de manglende parentesene. Arv Arv betyr noe annet i den objekt-orienterte verden enn det gjør i virkeligheten; her er det ingen dødsfall involvert. Når vi snakker om arv i OOP, snakker vi i en mer evolusjonsbasert måte. En Hund-klasse kan gjerne arve fra klassen Dyr. En Rottweiler-klasse vil arve fra klassen Hund. Dette gjør det mulig å lage enkle hierarkier, hvor man kan endre på små ting ved oppførselen. For eksempel ville jeg utvidet det forrige eksempelet på denne måten; class Hund // standardutstyr på en hund protected $bein = 4; protected $hale = TRUE; // navnet er individuelt protected $navn; // lag en ny hund med et gitt navn public function construct($navn) $this->navn = $navn; // lager en typisk hundelyd public function laglyd() echo $this->navn." sier: Voff!<br/>"; // lar hunden vår logre med halen public function logremedhale() echo $this->navn." logrer med halen!<br/>";
65 Kapittel 7. Objekt-orientering 65 class Rottweiler extends Hund protected $hale = FALSE; // overskriver funksjonen i Hund public function laglyd() echo $this->navn." sier: Grr!<br/>"; public function logremedhale() echo $this->navn." prøver å logre med ". "halen, men oppdager at rottweilere ". "ikke har hale!<br/>"; $fido = new Rottweiler("Fido"); $fido->laglyd(); $fido->logremedhale(); Det viktige i eksempelet ovenfor er nøkkelordet extends i definisjonen av Rottweiler. Det sier at vi arver alle egenskapene til Hund-objektet. Det er i PHP bare mulig å arve fra en foreldreklasse. Vi definerer så noen av tingene på nytt, slik som $hale, som vi setter til usann som standard på en Rottweiler. Vi definerer også metodene laglyd() og logremedhale() på nytt, fordi vi ønsker at disse skal ha forskjellig oppførsel når vi jobber med et Rottweiler-objekt. En Rottweiler har altså alle de samme egenskapene og metodene som en Hund, men oppførselen kan være annerledes. Vi hadde ikke trengt å definere laglyd()-metoden i Rottweiler-klassen, men vi kunne likevel brukt metoden uten å tenke på hvor den er definert. I så tilfelle ville den pekt tilbake på laglyd()-metoden i Hund-klassen. I dette tilfellet kaller vi Hund for grunnklassen (eng. "base class"), og Rottweiler for subklassen (eng. "subclass"). Hund blir også omtalt som foreldreklassen til Rottweiler, og vi sier at Rottweiler arver fra Hund. Synlighet I eksemplene til nå har vi sett flere nøkkelord som vi ikke har forklart, blant annet protected og public. I tillegg finnes et nøkkelord private som kan plasseres på samme plass. Disse nøkkelordene angir synligheten til en egenskap eller en metode. Du kan tenke på synlighet som en form for tilgangskontroll, dine foreldres hus og alle dets egenskaper er f.eks. (sannsynligvis) protected, som betyr at du (en subklasse av dine foreldre) har tilgang. Den mest restriktive formen for synlighet er private. Private metoder og variabler kan bare benyttes av funksjoner som tilhører klassen, men ikke av subklasser. Her er et eksempel;
66 66 Kapittel 7. Objekt-orientering class Forelder private $variabel = 2; public function ForeldreMetode() echo 'Variabel er '.$this->variabel. " (fra Forelder::ForeldreMetode)\n"; class Barn extends Forelder public function BarnMetode() // dette feiler! echo 'Variabel er '.$this->variabel. " (fra Barn::BarnMetode)\n"; $forelder = new Forelder(); $barn = new Barn(); $forelder->foreldremetode(); // OK $barn->foreldremetode(); // OK $barn->barnmetode(); // ingen advarsel, men feiler // disse to linjene blir aldri kjørt, // PHP gir feil echo 'Variabel er '.$forelder->variabel. ' (på $forelder)'."\n"; echo 'Variabel er '.$barn->variabel. ' (på $barn)'."\n"; De to første kallene, som kaller ForeldreMetode() vil være vellykkede, men BarnMetode() har ikke tilgang på $this->variabel fordi denne er private, og vil derfor bare skrive ut "Variabel er ". Når vi prøver å få tilgang til variabelen fra helt utenfor objektet, får vi en fatal feil fra PHP, og skriptet slutter å kjøre. Her er resultatet av å kjøre dette skriptet. Variabel er 2 (fra Forelder::ForeldreMetode) Variabel er 2 (fra Forelder::ForeldreMetode) Variabel er (fra Barn::BarnMetode) Fatal error: Cannot access private property Forelder::$variabel in /var/www/tests/php-guide/7/5.php on line 29 Om vi endrer $variabel til å være protected i eksempelet ovenfor, vil Barn få tilgang til $variabel, men den vil fremdeles være utilgjengelig fra utsiden av klassen. Med denne lille endringen får vi følgende utdata: Variabel er 2 (fra Forelder::ForeldreMetode) Variabel er 2 (fra Forelder::ForeldreMetode) Variabel er 2 (fra Barn::BarnMetode) Fatal error: Cannot access protected property Forelder::$variabel in /var/www/tests/php-guide/7/5.php on line 29 Som du kan se fikk vi nå tilgang til $variabel fra BarnMetode(), men vi kan likevel ikke hente verdien uten fra objektet. For å få til det må vi gjøre variabelen public, og om vi gjør endringen blir resultatet slik;
67 Kapittel 7. Objekt-orientering 67 Variabel er 2 (fra Forelder::ForeldreMetode) Variabel er 2 (fra Forelder::ForeldreMetode) Variabel er 2 (fra Barn::BarnMetode) Variabel er 2 (på $forelder) Variabel er 2 (på $barn) Statiske metoder og variable En statisk metode eller variabel, er noe som er felles for alle instanser av en klasse. I stedet for å kalle en metode på et faktisk objekt, kan en statisk metode kalles direkte på klassen. En statisk variabel er lik for alle instansene av en klasse, og om du setter den i et objekt, så vil alle objektene observere den nye verdien. Selve muligheten for å gjøre noe statisk kan virke noe forvirrende i begynnelsen, fordi hele poenget med objekt-orientering var å gruppere data og oppførsel, men ved å lage metoder som jobber på klassen og ikke på enkeltobjekter forsvinner noe av dette. Statiske medlemmer er derimot veldig nyttig om man vil gruppere felles oppførsel for en klasse når det gjelder ting som ikke nødvendigvis har noe med et enkelt objekt å gjøre. En vanlig ting å gjøre med statiske metoder og medlemsvariabler er å implementere et såkalt Singleton-pattern. Det blir benyttet til å sørge for at det alltid kun finnes en instans av klassen. Her er en implementasjon; class Singleton private static $singletonobject; public static function GetInstance() if (!isset(self::$singletonobject)) self::$singletonobject = new self(); return self::$singletonobject; public $variabel; $singleton = Singleton::GetInstance(); $singleton->variabel = 3; print_r($singleton); $nr2 = Singleton::GetInstance(); print_r($nr2); Statiske medlemsvariabler og metoder deklareres med nøkkelordet static, og det må skje etter du har angitt synligheten. Du trenger ikke å angi synlighet for statiske funksjoner og variabler, standard synlighet blir da satt til public. Den vante variabelen $this er naturlig nok ikke tilgjengelig i statiske metoder, siden vi ikke har et objekt å jobbe på. I stedet benytter vi self (merk at det ikke er noe dollar-tegn foran navnet, siden det ikke er en variabel). self peker på klassen den kjører i, og vi kunne i dette tilfellet like gjerne ha byttet ut self med Singleton alle plasser vi har brukt det.
68 68 Kapittel 7. Objekt-orientering For å få tilgang til statiske metoder og variable, bruker vi en annen syntaks enn vi gjør på objekter. Klassenavnet, umiddelbart etterfulgt av to kolon, og deretter variabelnavnet (med dollartegnet foran) eller funksjonsnavnet gjør trikset. Det kan være verdt å bite merke i at man fra en statisk metode har tilgang til både private, beskyttede og offentlige variabler og metoder i objekter laget av den samme klassen. Eksempelet under skriver ut tallene 1, 2 og 3; class TilgangsTest public static function BrukObject($objekt) echo $objekt->var1,"\n"; echo $objekt->var2,"\n"; echo $objekt->var3,"\n"; private $var1 = 1; protected $var2 = 2; public $var3 = 3; $a = new TilgangsTest(); TilgangsTest::BrukObject($a); Det finnes selvsagt mange andre bruksområder for statiske metoder og variable, men dette gir deg en grunnleggende innføring i prinsippet bak dem. Singleton-klassen vår over er ikke komplett, men det finns to gode implementasjoner 19 i PHP-manualen (den beste finnes i kommentarene nederst på siden). Objekt-operasjoner Den oppmerksomme leser har gjerne lagt merke til at objekter på en måte er en utvidelse av array-konseptet, og det er derfor en rekke operasjoner man kan utføre på objekter som man også kan gjøre på arrayer. Ved å bruke en standard foreach-løkke kan man gå gjennom alle de synlige medlemsvariablene i et objekt. Det gjør det mulig å skrive ut innholdet i et objekt på en enkel måte. Legg merke til at det stod synlige medlemsvariabler over; om du forsøker dette i en metode som ikke er en del av klassen objektet tilhører vil du kun se medlemsvariabler merket public. Et eksempel på denne typen objekt-iterasjon 20 finner du i PHP-manualen. Serialisering serialize() er en funksjon som kan ta en hvilken som helst variabel i PHP og gjøre den om til en verdi som du kan lagre. Funksjonen blir som oftest brukt sammen med arrayer, men vi gjennomgikk den ikke da vi så på disse. Den brukes sammen med unserialize(), som tar den lagrede verdien og gjør den om til en PHP-variabel igjen. serialize() går litt utenfor det vi har lært til nå, og lagrer både private, beskyttede og offentlige verdier i et objekt. Dette er nyttig om vi har et stort objekt som vi vil sende over nettet, eller lagre til senere. En viktig ting å bite merke i, er at for å rekonstruere et objekt fra en slik verdi trenger man også klassedeklarasjonen. Det er kun objekt-verdiene som blir lagret i den serialiserte strengen, og
69 Kapittel 7. Objekt-orientering 69 metoder og klassestruktur ellers blir ikke lagret. Det må man gjerne tenke over når man overfører objekter på denne måten mellom ulike systemer; klassen må finnes i begge ender. Her er et raskt eksempel som viser serialisering og rekonstruering av et objekt; class Test private $private = "a"; protected $protected = "b"; public $public = "c"; $a = new Test(); $a->public = "ny verdi"; $serialisert = serialize($a); $objekt = unserialize($serialisert); echo $objekt->public; Husk at serialize() og unserialize() også fungerer på arrayer, og at det er her de er mest brukt. Oppsummering I dag har vi introdusert helt nye konsepter; klasser og objekter. Disse gjør det mulig å gruppere data og funksjonalitet i en og samme innkapsling, og er svært mye brukt i større systemer. Du vil også komme over dem i PHP-manualen med jevne mellomrom. Om du ønsker å se mer på hvordan objekt-systemet i PHP fungerer, er denne siden 21 i PHPmanualen å anbefale på det sterkeste. Neste gang begynner vi å se på lagring i databaser, ved å bruke databasesystemet MySQL. Det er svært mye vi skal se på før vi kommer til hvordan vi integrerer MySQL med PHP, siden databaser er et relativt avansert og annerledes emne enn programmering. 21
70 70 Kapittel 8. Databaser og MySQL Kapittel 8. Databaser og MySQL Vi har til nå dekket svært mye av språket PHP; nå tar vi tak i MySQL og introduserer begreper som relasjonsdatabase. For å lage en virkelig dynamisk nettside trenger man en database i bakgrunnen. De aller fleste nettsidene undertegnede har utviklet opp gjennom årene har hatt en database i bakgrunnen. Hardware.no har f.eks. flere store relasjonsdatabaser som lagrer artikler, forumposter og forumbrukere. En database er i dag ganske lett å sette opp, og vil i de fleste tilfeller gi deg en svært dynamisk og rask nettside. Mange kjenner nok databasebegrepet gjennom produkter som Microsoft Access, men bakgrunnen for databaser er mer kompleks. Databaser begynte ganske enkelt som filer hvor man lagret strukturert data, gjerne oppdelt av spesielle tegn. Såkalte komma-avgrensede filer er et eksempel på denne tankegangen. Etter hvert utviklet man flere ulike modeller for databaser; den hierarkiske modellen er i dag brukt blant annet når man behandler XML-filer. Den mest populære modellen, som også er den modellen vi utelukkende skal konsentrere oss om i denne guiden, er den relasjonelle modellen. Relasjonsdatabaser lar deg definere relasjoner (sammenhenger) mellom ulike typer data i databasen, og det er mulig å sette sammen data på alle mulige måter. Relasjonsdatabaser består av tabeller. I en tabell finner man en gitt type data, og tabellen er oppdelt i kolonner og rader. En kolonne kan best beskrives som en overskrift i en tabell, og man angir når man oppretter tabellen hvor mange kolonner den har, og hva som kan lagres i hver enkelt kolonne. Selve dataene i en tabell er radene. Som en hovedregel inneholder en rad en dataverdi for hver kolonne i tabellen. MySQL er det mest populære relasjonsdatabasesystemet som også er gratis. Det baserer seg på en dialekt av SQL (Structured Query Language, uttales "SQL" eller som engelsk "sequel"), som er et språk som har vært i bruk i de aller fleste databasesystemer siden slutten av 80-tallet. Det betyr at det aller meste av det du lærer deg om MySQL også er overførbart til andre databasesystemer senere, med små endringer. Tilgang til MySQL Vi antar i dag at du innstallerte XAMPP som vi beskrev i kapittel 1 av denne guiden, eller at du kjører et Debian-basert Linux-system. I så fall kan du installere MySQL ved å skrive "apt-get install mysql-server" som root. Om du ønsker å installere alt fra bunnen selv, finner du instruksjoner 22 i MySQL-manualen. Uansett om du benytter Linux/Unix eller Windows, vil bruken av MySQL være lik med en gang du har funnet de kjørbare filene. På Linux ligger disse i stien, mens med XAMPP på Windows finner du dem i C:\Program files\xampp\mysql\bin. Undertegnede jobber på Linux for øyeblikket, så det blir antatt i eksemplene nedenfor. For å opprette en oppkobling til MySQL fra kommandolinjen, benytter du deg av programmet mysql (mysql.exe på Windows). Om du ikke har satt noe passord på root-kontoen din, kobler du opp ved å bare skrive "C:\Program files\xampp\mysql\bin\mysql.exe" på Windows, eller bare mysql på Linux. Men dersom du har satt opp et root-passord, må du gjøre følgende; "C:\Program files\xampp\mysql\bin\mysql.exe" -p 22
71 Kapittel 8. Databaser og MySQL 71 Merk at passordet skrives ikke på kommandolinjen, men du får spørsmål om det når du starter MySQL. Om du også har satt opp en ekstra bruker som du ønsker å benytte, må du bruke -u, og dersom du ønsker å koble til en MySQL-database på en annen datamaskin, bruker du -h. Om alt går som det skal, ser det gjerne slik ut; mysql -h localhost -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is to server version: a-Debian_9-log Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> Dette kalles MySQL-prompten. Her kan du skrive inn spørringer til MySQL. Om du ønsker å teste, kan du skrive "SHOW DATABASES;" og trykke enter. Du vil da få opp en liste over databasene som finnes på denne MySQL-installasjonen. Alle spørringer i MySQL avsluttes med et semikolon, så du kan spre spørringen din over flere linjer. Når du nå har fått MySQL opp å kjøre, kan du lage din test-database, som vi kaller "php_guiden". For å opprette denne databasen skriver du bare "CREATE DATABASE php_guiden". Merk at på Linux er database-navn (og tabellnavn) i MySQL versal-sensitive, slik at "php_guiden" er ikke det samme som "PHP_guiden". For å ta i bruk den nye databasen din, skriv "USE php_guiden;", og trykk enter. Her er en rask oversikt over hvordan dette så ut på mitt system; mysql> CREATE DATABASE php_guiden; Query OK, 1 row affected (0.00 sec) mysql> USE php_guiden; Database changed mysql> På neste side ser vi på datatypene i MySQL, og vi kommer ikke til å bruke databasen vi opprettet her før på siden etterpå. Om du valgte å kalle din database noe annet, noter ned navnet så du husker det. Datatyper Før man kan lagre data i databasen vår, er vi nødt til å bestemme strukturen på dataene vi vil lagre. Denne strukturen defineres av en tabell-definisjon (noen ganger kalt et tabell-skjema). Som vi har nevnt tidligere, består en tabell av kolonner, og vi må bestemme hvilke data hver kolonne skal inneholde. Til forskjell fra PHP, er vi i MySQL nødt til å definere hvilken type data som skal lagres i hver kolonne. Det finnes mange datatyper i MySQL, og her er en liste over de viktigste;
72 72 Kapittel 8. Databaser og MySQL Navn Hva den lagrer Tall TINYINT SMALLINT MEDIUMINT INT BIGINT DOUBLE BOOL Lagrer et heltall mellom -128 og 127. Ved å sette nøkkelordet UNSIGNED foran, endres rekkevidden til 0 til 255. Lagrer et heltall mellom og Ved å sette nøkkelordet UNSIGNED foran, endres rekkevidden til 0 til Lagrer et heltall mellom og Ved å sette nøkkelordet UNSIGNED foran, endres rekkevidden til 0 til Lagrer heltall, i rekkevidden til Ved å sette nøkkelordet UNSIGNED foran, endres rekkevidden til 0 til Er den vanligste datatypen for å lagre heltall. Lagrer heltall, i rekkevidden til Ved å sette nøkkelordet UNSIGNED foran, endres rekkevidden til 0 til Bør unngås om du ikke trenger å bruke så store tall. Lagrer flyttal ifølge IEEE-standarden. Tallet er nøyaktig til omtrent 15-desimalplasser. En boolsk verdi (TRUE/FALSE). I MySQL er TRUE definert som alle verdier som ikke er 0 eller NULL. Lagres som en TINYINT på disk. Tidspunkt DATE TIME DATETIME TIMESTAMP Lagrer en dato, på formatet ÅÅÅÅ-MM-DD. Lagrer et tidspunkt (uten datobiten) på formatet TT:MM:SS. Lagrer en dato og et tidspunkt, på formatet ÅÅÅÅ-MM-DD TT:MM-SS. Lagrer et tidspunkt som antall sekunder fra 1. januar 1970 kl. 00:00:00. Tekst CHAR(størrelse) VARCHAR(størrelse) TEXT MEDIUMTEXT CHAR-datatypen lagrer tekst i et felt med statisk størrelse. Du oppgir størrelsen på feltet i antall tegn (maksimum størrelse er 255). Uansett om du lagrer et tegn, eller så mange tegn som er tillatt, vil det ta størrelse når det lagres på disk (om teksten du lagrer ikke er lang nok, fylles den med NULL-tegn). Samme som CHAR, men kun den faktiske strengen lagres på disk. Noe tregere enn CHAR. Lagrer tekst med en lengde på opptil 2 16 bytes (64 KiB) med tekst. Bruker kun lengden på teksten som blir lagret på disk. Lagrer tekst med en lengde på opptil 2 24 bytes (16 MiB) med tekst. Bruker kun lengden på teksten som blir lagret på disk. LONGTEXT(størrelse) Lagrer tekst med en lengde på opptil 232 bytes (4 GiB) med tekst. Bruker kun lengden på teksten som blir lagret på disk.
73 Kapittel 8. Databaser og MySQL 73 Om du er interessert i resten av disse datatypene, eller detaljer om de enkelte, finner du dem i MySQL-manualen 23. Nå skal vi opprette vår første tabell. Tabeller Med all vår nyervervede kunnskap om datatyper, er det på tide å opprette vår første tabell. Tabellen vi lager skal brukes til å lagre en liste over personer, med fornavn, etternavn, fødselsdato og e-postadresse. For enkelhets skyld kaller vi tabellen vår person. For å opprette en tabell, bruker vi en SQL-setning som kalles CREATE TABLE. Uten å gå videre inn på syntaksen, presenterer vi bare spørringen her, og så skal vi gjennomgå den etterpå. Slik ser den ut når vi skriver den direkte inn i MySQL-prompten. mysql> CREATE TABLE person ( -> fornavn VARCHAR(255), -> etternavn VARCHAR(255), -> fodselsdato DATE, -> epost VARCHAR(255) -> ); Query OK, 0 rows affected (0.03 sec) MySQL indikerer nederst at spørringen var OK, og at ingen rader ble påvirket, noe som betyr at vi ikke satte inn noe faktisk data. Syntaksen for CREATE TABLE er ganske enkel; først kommer navnet på tabellen vi skal lage. Deretter følger deklarasjonen av kolonnene, separert av komma. En kolonne begynnes med navnet på kolonnen, etterfulgt av datatypen og en eventuell størrelse (merk at DATE ikke krever noen størrelse). Om du vil sjekke om tabellen din ble korrekt opprettet, prøv å skrive "DESCRIBE person;". Forhåpentligvis blir resultatet som følger; mysql> DESCRIBE person; Field Type Null Key Default Extra fornavn varchar(255) YES NULL etternavn varchar(255) YES NULL fodselsdato date YES NULL epost varchar(255) YES NULL rows in set (0.00 sec) Hver rad som vi nå setter inn i person-tabellen, vil nå bestå av et fornavn, et etternavn, en fødselsdato og en e-postadresse. Om du ser i Default-kolonnen i beskrivelsen, ser du også at alle disse verdiene kan settes til NULL (tilsvarer NULL i PHP), og at dette faktisk er standardverdien. Vi ønsker nå gjerne å sette inn noe data i tabellen vår, slik at vi har noe å teste mot. Vi gjør dette enkelt ved å bruke en INSERT INTO-spørring; mysql> INSERT INTO person (fornavn, etternavn, fodselsdato, epost) -> VALUES ('Vegard', 'Larsen', ' ', 'vegard AT hardware.no'); Query OK, 1 row affected (0.00 sec) Du får en indikasjon på at innsettingen var vellykket, og at en rad i tabellen ble påvirket. Du kan sette inn flere rader, slik at vi har noe å teste med; 23
74 74 Kapittel 8. Databaser og MySQL mysql> INSERT INTO person (fornavn, etternavn, fodselsdato, epost) -> VALUES -> ('Ola', 'Nordmann', ' ', 'ola AT eksempel.no'), -> ('Kari', 'Nordkvinne', ' ', 'kari AT eksempel.no'), -> ('Per', 'Olsen', ' ', 'per AT eksempel.no'), -> ('Knut', 'Olsen', ' ', 'knut AT eksempel.no'); Query OK, 4 rows affected (0.00 sec) Records: 4 Duplicates: 0 Warnings: 0 Her ser du at vi har satt inn flere verdier i en spørring, og at vi får noe mer informasjon ut fra MySQL i dette tilfellet. Nå har vi nok data til å begynne å undersøke innholdet i tabellen. Uthenting av data Vi har til nå lagd en tabell, og satt inn noe data i den. Du har kanskje satt inn noe ekstra data i forhold til hva jeg gjorde, og det går bra; men du kan få forskjellige resultater enn vi gjør i våre eksempler her. Siden tabellen vår er så liten (den har bare 5 rader), kan det være praktisk å hente ut alle dataene som er her; og det gjøres svært enkelt med en SELECT-spørring; mysql> SELECT * FROM person; fornavn etternavn fodselsdato epost Vegard Larsen vegard AT hardware.no Ola Nordmann ola AT eksempel.no Kari Nordkvinne kari AT eksempel.no Per Olsen per AT eksempel.no Knut Olsen knut AT eksempel.no rows in set (0.00 sec) Her ser du at vi har fått ut dataene i den rekkefølgen vi la den inn (det er ikke nødvendigvis tilfellet). Alt vi har lagt inn er der fremdeles. * indikerer at vi vil ha data fra alle kolonner i tabellen. Det er gjerne ikke så interessant, sett at vi ville ha listen alfabetisert etter etternavn; mysql> SELECT * FROM person ORDER BY etternavn; fornavn etternavn fodselsdato epost Vegard Larsen vegard AT hardware.no Kari Nordkvinne kari AT eksempel.no Ola Nordmann ola AT eksempel.no Per Olsen per AT eksempel.no Knut Olsen knut AT eksempel.no rows in set (0.00 sec) Om du studerer listen nøye, ser du gjerne at Per kommer før Knut, selv om det alfabetisk ikke er korrekt. En ny spørring fikser på det;
75 Kapittel 8. Databaser og MySQL 75 Du kan selvsagt bruke ORDER BY til å sortere på de andre kolonnene også; f.eks. kan du rangere etter alder slik som dette; Her har vi lagt til nøkkelordet DESC (en forkortelse for descending) for å indikere at vi ønsker den største datoen først, dvs. den yngste personen. Kanskje er vi bare interessert i å hente ut en gitt kolonne fra tabellen vår, la oss si at vi skal lage en e-postliste og vi bare trenger e-postadressene; Som du ser kan vi bruke MySQL til å hente ut nøyaktig den informasjonen vi trenger fra en tabell, ved å benytte enkle spørringer. Mer uthenting Til nå har vi bare sortert utdataene når vi henter data fra MySQL, men det er ofte mye nyttigere å bare hente ut den nøyaktige informasjonen vi trenger. Til dette bruker vi en såkalt WHEREklausul, som lar deg velge bort rader ved hjelp av samme logikk som vi benytter i PHP. Likhet mysql> SELECT * FROM person ORDER BY etternavn, fornavn; fornavn etternavn fodselsdato epost Vegard Larsen vegard AT hardware.no Kari Nordkvinne kari AT eksempel.no Ola Nordmann ola AT eksempel.no Knut Olsen knut AT eksempel.no Per Olsen per AT eksempel.no rows in set (0.00 sec) mysql> SELECT * FROM person ORDER BY fodselsdato DESC; fornavn etternavn fodselsdato epost Per Olsen per AT eksempel.no Vegard Larsen vegard AT hardware.no Ola Nordmann ola AT eksempel.no Knut Olsen knut AT eksempel.no Kari Nordkvinne kari AT eksempel.no rows in set (0.00 sec) mysql> SELECT epost FROM person; epost vegard AT hardware.no ola AT eksempel.no kari AT eksempel.no per AT eksempel.no knut AT eksempel.no rows in set (0.00 sec) Sett at vi lurer på om det er noen som har bursdag i dag i databasen vår (det er det ikke, så vi får et tomt resultat);
76 76 Kapittel 8. Databaser og MySQL mysql> SELECT * FROM person WHERE fodselsdato = CURDATE(); Empty set (0.00 sec) Selv om resultatet er tomt, illustrerer det to viktige ting; først og fremst at det finnes mange innebygde funksjoner i MySQL. Her bruker vi funksjonen CURDATE() til å hente ut dagens dato. For det andre benytter vi oss av en WHERE-klausul som sier at vi kun ser etter personer som har en gitt fødselsdato. Du kan også se at i MySQL bruker vi et enkelt likhetstegn for å sjekke om noe er likt, mens vi i PHP må benytte to likhetstegn. Vi kan også se etter personer som har et gitt etternavn; mysql> SELECT * FROM person WHERE etternavn = 'Olsen'; fornavn etternavn fodselsdato epost Per Olsen per AT eksempel.no Knut Olsen knut AT eksempel.no rows in set (0.00 sec) Vi bruker også her likhetstegnet for å sjekke at innholdet i en kolonne er en gitt verdi, men denne gangen gjør vi det på en string-kolonne. Kanskje vi ønsker å finne alle som har et etternavn som begynner på bokstaven N? Da må vi bruke en annen sammenligning. Strenglikhet mysql> SELECT * FROM person WHERE etternavn LIKE 'N%'; fornavn etternavn fodselsdato epost Ola Nordmann ola AT eksempel.no Kari Nordkvinne kari AT eksempel.no rows in set (0.00 sec) Her bruker vi sammenligningen LIKE, og prosenttegnet angir da et såkalt wildcard for å spesifisere at her kan det komme en rekke på flere bokstaver. Du kan sette inn prosenttegn flere plasser i søkestrengen, og du kan også plassere det fremst. For å finne alle som har e- postadresse hos Hardware.no kan du bruke denne spørringen; mysql> SELECT * FROM person WHERE epost LIKE '% AT hardware.no'; fornavn etternavn fodselsdato epost Vegard Larsen vegard AT hardware.no row in set (0.00 sec) Du kan også søke etter ikke-treff; om du vil ha personer som ikke jobber for Hardware.no, kan du bruke denne spørringen;
77 Kapittel 8. Databaser og MySQL 77 mysql> SELECT * FROM person WHERE epost NOT LIKE '% AT hardware.no'; fornavn etternavn fodselsdato epost Ola Nordmann ola AT eksempel.no Kari Nordkvinne kari AT eksempel.no Per Olsen per AT eksempel.no Knut Olsen knut AT eksempel.no rows in set (0.00 sec) Den eneste forskjellen fra spørringen over er ordet NOT før LIKE, og meningen er selvsagt. Om du skal gjøre det samme når du bruker likhetstegnet til å sammenligne, må du bytte ut likhetstegnet med!=, som er det samme som i PHP. Større enn/mindre enn Hva om du vil ha alle som født i eller etter 1977 (som gjør at de er 30 år eller yngre i år); mysql> SELECT * FROM person WHERE fodselsdato >= ' '; fornavn etternavn fodselsdato epost Vegard Larsen vegard AT hardware.no Per Olsen per AT eksempel.no rows in set (0.00 sec) Du kan her bruke en rekke av de samme sammenligningsoperatorene som i PHP, og de fungerer også på strenger. Om du vil ha alle som kommer etter Nordkvinne i telefonkatalogen, kan du bruke følgende spørring; mysql> SELECT * FROM person WHERE etternavn > 'Nordkvinne'; fornavn etternavn fodselsdato epost Ola Nordmann ola AT eksempel.no Per Olsen per AT eksempel.no Knut Olsen knut AT eksempel.no rows in set (0.00 sec) Selv om vi har utelukket alle som har et etternavn som er alfatbetisk mindre enn Nordkvinne, ser du at resultatet likevel ikke er sortert korrekt på fornavn og etternavn. Dette må vi spesifisere om vi ønsker, og det gjør vil på følgende måte; mysql> SELECT * FROM person -> WHERE etternavn > 'Nordkvinne' -> ORDER BY etternavn, fornavn; fornavn etternavn fodselsdato epost Ola Nordmann ola AT eksempel.no Knut Olsen knut AT eksempel.no Per Olsen per AT eksempel.no rows in set (0.00 sec) Det er viktig å bite seg merke i at WHERE alltid kommer før ORDER BY, men ellers er dette bare en sammenslåing av det du har lært til nå.
78 78 Kapittel 8. Databaser og MySQL Hva med NULL? Som vi nevnte tidligere, kan alle feltene i tabellen vår ha en NULL-verdi, som tilsvarer noe av det samme som det gjør i PHP. Vi bruker hovedsaklig verdien NULL i MySQL når det er en kolonne som ikke gjelder for denne raden. For eksempel, om vi skal legge inn musikkartisten Madonna i tabellen vår, ville vi gjort det med en NULL-verdi på etternavn og e-postadresse. Dette kan vi gjøre på en av to måter, enten ved å eksplisitt sette inn NULL i de relevante feltene når vi setter inn, eller lage en INSERT spørring der de relevante kolonnene ikke er nevnt. Her er begge metodene; mysql> INSERT INTO person (fornavn, fodselsdato) -> VALUES ('Madonna', ' '); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO person (fornavn, etternavn, fodselsdato, epost) -> VALUES ('Madonna', NULL, ' ', NULL); Query OK, 1 row affected (0.00 sec) Om du nå henter ut alle med fornavn Madonna fra databasen, vil du se følgende; mysql> SELECT * FROM person WHERE fornavn = 'Madonna'; fornavn etternavn fodselsdato epost Madonna NULL NULL row in set (0.00 sec) Om du skal lete etter personer som ikke har etternavn i databasen din, vil du måtte bruke en spesiell sjekk for å finne dem, fordi du kan ikke benytte WHERE etternavn = NULL i spørringen siden NULL er en spesialverdi. mysql> SELECT * FROM person WHERE etternavn = NULL; Empty set (0.00 sec) mysql> SELECT * FROM person WHERE etternavn IS NULL; fornavn etternavn fodselsdato epost Madonna NULL NULL row in set (0.00 sec) Som du ser krever NULL litt spesiell behandling om du skal hente ut data basert på slike verdier. Oppdatering Sett at du en dag oppdager at Madonna faktisk også har et etternavn 24, og du har lyst til å oppdatere dette i databasen din. Da kan du enten slette den originale raden og sette inn en ny, men dette kan føre til trøbbel med relasjoner til andre tabeller (som du ennå ikke har lært særlig mye om, og så har du ikke lært å slette noe enda). 24
79 Kapittel 8. Databaser og MySQL 79 For å oppdatere rader i tabellen er du nødt til å bruke en UPDATE-spørring. Den krever også en WHERE-klausul, ellers så endrer den alle rader i tabellen din til de nye verdiene. Du bruker den på følgende måte for å sette Madonnas korrekte fornavn og etternavn; mysql> UPDATE person SET -> fornavn = 'Madonna Louise', -> etternavn = 'Ciccone Ritchie' -> WHERE fornavn = 'Madonna' -> LIMIT 1; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 Selve UPDATE-biten av denne spørringen er ganske lett å forstå; vi oppdaterer både fornavnet og etternavnet med nye verdier. Dette gjør vi bare dersom fornavnet allerede er satt til 'Madonna'. Den siste linjen har du ikke sett før, og betyr rett og slett at MySQL bare får lov til å endre en enkelt rad. Du kan endre tallet dersom det er nødvendig. Du kan også benytte LIMIT sammen med SELECT-spørringer, og dette er veldig trygt å eksperimentere med. Strengt tatt er ikke LIMIT påkrevd i spørringen over, siden det faktisk kun finnes en rad i tabellen hvor fornavnet er eksakt lik 'Madonna', men den er kjekk å bruke som et sikkerhetsnett i tilfelle det var flere rader som hadde det samme fornavnet. Det kan ofte være lurt å sjekke på forhånd om de radene UPDATE faktisk vil endre er de samme som du ønsker å oppdatere. Det gjør du enklest ved å benytte nøyaktig samme WHERE-klausul i en SELECT-spørring. Du kan nå forsikre deg om at du har oppdatert den korrekte raden som du ønsket; mysql> SELECT * FROM person WHERE fornavn LIKE 'M%'; fornavn etternavn fodselsdato epost Madonna Louise Ciccone Ritchie NULL row in set (0.00 sec) Sletting Hva om du har informasjon i tabellen din som du ønsker å slette? La oss si at du ikke lenger liker Madonna, og ikke ønsker å ha henne i din kontaktliste; da er du nødt til å benytte deg av en DELETE-spørring. Før vi begynner, DELETE er akkurat like utsatt for å glemme WHERE-klausulen som UPDATE er. Derfor bør du alltid være veldig forsiktig når du forsøker å slette ting fra tabellene dine, og huske å ha med en tilstrekkelig WHERE-klausul, og gjerne også en LIMIT-bit. mysql> SELECT * FROM person WHERE fornavn LIKE 'Madonna%'; fornavn etternavn fodselsdato epost Madonna Louise Ciccone Ritchie NULL row in set (0.00 sec) mysql> DELETE FROM person WHERE fornavn LIKE 'Madonna%' LIMIT 1; Query OK, 1 row affected (0.00 sec)
80 80 Kapittel 8. Databaser og MySQL Vi sjekket først hvor mange rader det fantes med et fornavn som begynner med Madonna, og deretter kjører vi en DELETE-spørring med samme WHERE-klausul og en begrensning på antallet. Selve syntaksen til DELETE er ganske enkel, og trenger ikke videre forklaring. Oppsummering I dag har du lært det aller mest grunnleggende om relasjonsdatabaser, og MySQL spesielt. Du har lært at en database består av en eller flere tabeller, og at en tabell er oppbygd av kolonner og rader. Vi har vist deg hvordan du kobler opp mot en MySQL-database. Etterpå fortalte vi om de ulike datatypene en MySQL-tabell kan bestå av, før vi viste deg hvordan du kan lage dine egne tabeller, og hvordan du kan sette inn data i dem. Du har senere sett hvordan vi kan benytte MySQL til å finne spesifikk informasjon i databasen på en enkel måte, gjennom språket SQL. Her har du lært sortering og utvelgelse. Vi har vist deg hvordan du kan oppdatere data som du har lagt inn i databasen, og til slutt hvordan du kan slette disse dataene. Vi har også hatt en rask gjennomgang av den spesielle NULL-verdien.
81 Kapittel 9. Databasenormalisering 81 Kapittel 9. Databasenormalisering I forrige kapittel lærte vi deg det aller mest grunnleggende om databaser, i dag skal vi se på hvordan vi kan utnytte relasjonsdatabaser til det fulle. Forrige gang lærte vi deg det aller mest grunneleggende om databaser, og hvordan de er oppbygd. I dag skal vi lære deg hvordan du bør strukturere databasetabellene dine for å gjøre de lette å vedlikeholde og bruke, gjennom en prosess kalt normalisering. Etterpå skal vi se på hvordan vi kan benytte data fra flere tabeller i en spørring. Normalisering består av en rekke såkalte normalformer, hvor hver normalform er et trinn på veien til å få en normalisert tabell. Nøyaktig på hvilken normalform man bør stoppe er noe omdiskutert, men man sier som oftest at data er normalisert om det er på tredje normalform eller høyere. En vanlig forkortelse for første normalform er 1NF, og vi kommer til å bruke slike forkortelser utover i artikkelen. I dette kapittelet kommer vi til å presentere de tre første normalformene, som er de du kommer til å benytte til vanlig. Det finnes også flere normalformer, men disse er ikke relevante i majoriteten av tilfellene. Etter at vi har presentert de tre første normalformene, kommer vi til å gjennomgå vår løsning på dagens eksempel, og vi anbefaler at du utarbeider din egen løsning før du leser hva vi valgte å gjøre. Dagens eksempel Gjennom dette kapittelet bruker vi som eksempel lagring av en kontaktliste, og sammenhengen mellom dem, på en måte som et sosialt nettverk. Først og fremst ønsker vi å lagre en rekke ting om personer; Navn Et eller flere telefonnummer (markert jobb, hjemme, mobil) En eller flere e-postadresser (markert jobb, hjemme, mobil) Postadresse (hjemme) Fødselsdato Ektefelle Barn Venner og bekjente Dette kan virke som ganske mye informasjon nå i begynnelsen. Ved å gjennomgå normaliseringen kommer vi ganske enkelt frem til en god lagringsstruktur for dataene. I dette kapittelet kommer vi til å velge ut deler av disse dataene underveis, og gjøre normaliseringen på disse bitene av datasettet. Helt til slutt kommer vi til å presentere vår løsning på problemet, og det anbefales at du underveis forsøker å bruke teknikkene vi bruker på hele eksempelet. Da kan du sammenligne med vår løsning til slutt. Første normalform 1NF krever at hver rad i en tabell innehold er såkalt atomisk verdi; dvs. en verdi som ikke kan deles opp i flere verdier. Første normalform krever også at hver rad i tabellen unikt kan identifiseres gjennom en primærnøkkel. Om vi setter opp en rad med noen av kolonnene fra eksempelet på forrige side direkte i en tabell;
82 82 Kapittel 9. Databasenormalisering Navn Telefon Fødselsdato Ola Nordmann (h), (j), (m) 12. januar 1978 Slik tenker nok de aller fleste når de skal lage sin første tabell, og i denne tabellen ville jeg gjerne også hatt med egne kolonner for postadresse, ektefelle, barn og venner om eksempelet skulle vært komplett. Atomiske verdier Første biten av første normalform sier at hver rad bør inneholde en atomisk verdi; dvs. at en verdi ikke kan representere flere verdier. Ovenfor ser du at Telefon-kolonnen har tre verdier for Olas telefonnummer, og det er ikke tillatt i 1NF, og vi er nødt til å splitte disse verdiene opp. Navn Telefon Fødselsdato Ola Nordmann (h) 12. januar 1978 Ola Nordmann (j) 12. januar 1978 Ola Nordmann (m) 12. januar 1978 I stedet for å ha en enkelt rad som representerer Ola, har vi nå tre rader, bare for å representere telefonnummeret. Unike rader Sett at Ola jobber i lag med en navnebror som tilfeldigvis er født på samme dag, og jobbtelefonnummeret hans er det samme som Olas (selskapets sentralbord). Vi får nå problemer med å identifisere hvilke rader som hører til hvilken Ola; Navn Telefon Fødselsdato Ola Nordmann (h) 12. januar 1978 Ola Nordmann (j) 12. januar 1978 Ola Nordmann (m) 12. januar 1978 Ola Nordmann (j) 12. januar 1978 Ola Nordmann (m) 12. januar 1978 For å løse dette problemet må vi lage en primærnøkkel; dvs. en nøkkel som unikt kan identifisere en rad i en tabell. Om du har et sett med verdier som du alltid vet er unike, kan du bruke dem; i Norge kunne fødselsnummeret til en person vært et godt valg når man lagrer personopplysninger. Det er derimot ikke tillatt å lagre til vanlig, og vi bruker derfor bare et unikt tall;
83 Kapittel 9. Databasenormalisering 83 Id.* Navn Telefon Fødselsdato 1 Ola Nordmann (h) 12. januar Ola Nordmann (j) 12. januar Ola Nordmann (m) 12. januar Ola Nordmann (j) 12. januar Ola Nordmann (m) 12. januar 1978 Nå er det ikke lenger noe problem å finne frem til en enkelt rad i databasen, men du kan se at vi ikke kan se forskjell på hvilken Ola det er snakk om. Grunnen til dette ser vi når vi går videre i normalformene. I noen tilfeller kan primærnøkkelen også være en sammensetning av kolonner i tabellen, der du alltid vet at alle kombinasjoner er unike. Primærnøkkelen vi nå laget er en såkalt enkel primærnøkkel, mens en primærnøkkel som består av flere kolonner er en sammensatt primærnøkkel. Vi markerer primærnøkler med en stjerne på slutten av navnet. Andre normalform Den andre normalformen krever at alle data i en tabell er avhengige av hele primærnøkkelen. Om det er data i tabellen som bare delvis er avhengig av primærnøkkelen, må de splittes ut i separate tabeller. Kravene for å nå andre normalform er altså at tabellen må være i første normalform, og at alle kolonner som ikke er nøkler er totalt avhengig av hele nøkkelen i tabellen. Om vi ser på vår kontaktliste igjen, kunne en representasjon av en person og hans arbeidsplass vært følgende; PersonID* ArbeidsgiverID* Navn Arbeidsgiver Kontor 1 23 Ola Nordmann Hardware Online AS 231 Vi har her oppgitt en arbeidsgiver-id, siden det gjerne er flere som jobber hos Hardware Online AS; og det er derfor naturlig at denne IDen er en del av primærnøkkelen. En persons navn er kun avhengig av PersonID, mens navnet på arbeidsgiveren kun er avhengig ArbeidsgiverID. Kontoret er derimot avhengig av både ArbeidsgiverID og PersonID. Det gjør at det blir naturlig å dele denne opp i tre tabeller; en som angir personinformasjon, en som gir arbeidsgiverinformasjon, og en som setter opp en kobling mellom disse. Person PersonID* Navn 1 Ola Nordmann Arbeidsgiver ArbeidsgiverID* Navn 23 Hardware Online AS
84 84 Kapittel 9. Databasenormalisering Arbeidsforhold PersonID* ArbeidsgiverID* Kontor Som du kan se, har vi nå delt vår originale tabell i tre forskjellige tabeller som alle er i 2NF. Selve arbeidsforholdet mellom en person og en arbeidsgiver er nå i en separat tabell. Det gjør at vi faktisk har fått utvidede muligheter i forhold til hva vi originalt tenkte oss; vi kan nå la en person være ansatt i flere firmaer. Ved å sette inn en ekstra kolonne i Arbeidsforhold som vi kaller "Stilling", kan vi også oppgi hvilken stilling man har. Derimot, siden Arbeidsforhold har en kombinert primærnøkkel på PersonID og ArbeidsgiverID, er det ikke mulig for en person å være ansatt med to forskjellige stillinger i en bedrift. Hvordan ville du fikset det? Tredje normalform Den tredje normalformen krever at alle data i en tabell ikke er avhengig av data som ikke er en del av en nøkkel. Kravene for å nå tredje normalform er altså at tabellen må være i andre normalform, og at alle kolonner som ikke er nøkler ikke er avhengig av andre kolonner som heller ikke er nøkler. Om vi ser på vår kontaktliste igjen, kunne en representasjon av postadressen til en person vært følgende; PN Navn Gate Nr Postnummer Poststed 1 Ola Nordmann Blåklokkeveien Ørsta I denne tabellen er det to avhengigheter som kan omfattes av tredje normalform; poststed er ikke avhengig av primærnøkkelen i tabellen, men av postnummeret (men postnummeret er avhengig av primærnøkkelen). Gatenummeret er avhengig av primærnøkkelen, men også av gatenavnet og postnummeret. Den er litt verre å se, men det er på grunn av at noen gater ikke har gitte gatenummer. Denne er derimot så obskur og vanskelig å implementere at den ignoreres, og det er ikke uvanlig å foreta slike forenklinger. I dette tilfellet vil det være praktisk umulig å gjøre noe med, og derfor ignorerer vi den. Men vi er likevel nødt til å gjøre noe med koblingen mellom postnummer og poststed. Siden poststed er det eneste som er avhengig av postnummer, blir tabellen vi splitter disse to ut i svært liten; Postnummer Poststed 6150 Ørsta Vi kan bruke postnummeret som primærnøkkel for denne tabellen, siden postnummeret garantert er unikt. Den andre tabellen blir da seende slik ut; PN Navn Gate Nr Postnummer 1 Ola Nordmann Blåklokkeveien
85 Kapittel 9. Databasenormalisering 85 Det eneste som har skjedd her, er at vi har fjernet poststed fra tabellen. Om vi hadde måttet introdusert en ny primærnøkkel i postnummer-tabellen vår, ville vi hatt den nye primærnøkkelen oppgitt i postnummer-feltet i denne tabellen i stedet. Og vi får også redusert datamengden det er snakk om, i alle fall om vi har mange innbyggere fra samme område i databasen. Posten Norge leverer en nedlastbar liste med postnummer og poststed 25 som du kan bruke til å fylle den første tabellen med. Som du kan se, har vi ikke tapt noen informasjon på å gå over fra andre til tredje normalform. Vi har faktisk spart lagringsplass i det lange løp, selv om tabellen som inneholder alle postnumrene kan bli ganske stor. Før du går videre til neste delkapittel, anbefaler vi at du forsøker å utarbeide din egen løsning på dagens eksempel. Sett opp et databaseskjema, og legg inn litt eksempeldata for å se om databaseskjemaet gjør det du vil. Løsning Vår løsning inneholder ingenting utover det som er definert i eksempelet, selv om det gjerne er lett for å nettopp gå utover det som er definert i eksempelet. Eksempelet i seg selv er ikke særlig realistisk; og vi skal være de første til å innrømme at vår løsning heller ikke er perfekt. Vi skal diskutere manglene i denne løsningen etterhvert. Først til presentasjonen; Tegningen over er et såkalt entitets-relasjonsdiagram laget i verktøyet MyDBExpert 26. Verktøyet er ærlig talt særdeles dårlig; men det ble skrevet av undertegnede for tre år siden, og jeg er dermed særdeles fortrolig med det. Om du skal lage tilsvarende diagrammer selv, bør du nok lete deg frem til et annet alternativ. Under finnes MySQL-koden for å opprette en slik database som over
86 86 Kapittel 9. Databasenormalisering CREATE TABLE Epost ( PersonID INT, Epost VARCHAR(255) NOT NULL, Sted ENUM('Hjemme', 'Jobb', 'Mobil') NOT NULL, PRIMARY KEY (PersonID, Epost) ); # Table Epost CREATE TABLE Telefonummer ( PersonID INT, Nummer CHAR(12), Sted ENUM('Hjemme', 'Jobb', 'Mobil') NOT NULL, PRIMARY KEY (PersonID, Nummer) ); # Table Telefonummer CREATE TABLE Poststed ( Postnummer INT(4), Poststed VARCHAR(255) NOT NULL, PRIMARY KEY (Postnummer) ); # Table Poststed CREATE TABLE Person ( PersonID INT, Navn VARCHAR(255) NOT NULL, Fodselsdato DATETIME NOT NULL, Gate VARCHAR(255) NOT NULL, Postnummer INT(4) NOT NULL, PRIMARY KEY (PersonID) ); # Table Person CREATE TABLE PersonligForhold ( PersonID1 INT NOT NULL, PersonID2 INT NOT NULL, Type ENUM('Ektefelle', 'Barn', 'Foreldre', 'Venn', 'Kollega') NOT NULL, PRIMARY KEY(PersonID1, PersonID2) ); # Table PersonligForhold Person-tabellen er ganske enkel, og består av ting som kun er avhengig av denne personen. Den gir også en person en unik ID som man kan bruke for å referere til denne personen i etterkant. Vi har valgt å ha to enkle tabeller for Epost og Telefonnummer; det gjør det enklere for oss å søke etter et gitt telefonnummer. Et annet alternativ ville vært å splitte Telefonnummer-tabellen i tre ulike tabeller; HjemmeTelefon, JobbTelefon og MobilTelefon. Om vi da hadde et ukjent nummer ville vi da vært nødt til å søke i tre forskjellige tabeller. I vår løsning benytter vi i stedet oss av en spesiell datatype i MySQL; ENUM, som lar deg spesifisere nøyaktig hva som kan stå i den kolonnen. Poststed og postnummer har vi også delt ut til en egen tabell; som vi beskrev når vi snakket om tredje normalform. Vi har tatt og sett på alle typer personlige forhold i en egen tabell. Vi angir to personer på hver rad, og sier hvilket forhold disse to har. Det gir oss veldig lett alle kontaktene til en gitt person; f.eks. om vi ønsker å slå opp alle personer som begge kjenner. Svakheter PersonligForhold-tabellen er også vår løsnings største svakhet. Her er det vi betrakter som de to største feilene; Forhold går alltid to veier, så vi må enten legge inn to rader for hvert personlige forhold (med person 1 og 2 reversert i rad 2), eller gjøre at alle spørringer tar hensyn til at person 1 og 2 kan være byttet om.
87 Kapittel 9. Databasenormalisering 87 En normalt enkel spørring for å finne ektefellen til en person går dermed fra å være; SELECT p.navn FROM Person AS p, PersonligForhold AS f WHERE f.personid2 = p.personid AND f.personid1 = 23 AND f.type = 'Ektefelle';... til å bli; SELECT p.navn FROM Person AS p, PersonligForhold AS f WHERE f.type = 'Ektefelle' AND ( (f.personid2 = p.personid AND f.personid1 = 23) OR (f.personid1 = p.personid AND f.personid2 = 23) ); En person kan bli gift med seg selv eller være sin egen beste venn. Tabellen forhindrer oss ikke å si at en person er sitt eget barn eller at en person har flere ektefeller. Dette kunne vært delvis forhindret ved å flytte ektefelleid som et felt i Person-tabellen, og si at alle personer har et ForeldreID som peker til en annen person. Likevel stopper ikke dette tilfeller der man er sin egen beste venn, eller å si at man er gift med seg selv. Dette er mulig å løse på databasenivået ved hjelp av såkalte restriksjoner, men dette er langt utenfor hva vi kommer til å dekke i denne artikkelserien. Oppsummering Normalisering av en database gjør dataene enklere å jobbe med, og forhindrer dobbellagring av data. Første normalform krever at alle rader ikke kan deles opp mer; og at hver rad kan identifiseres ved hjelp av en primærnøkkel. Andre normalform krever at alle ikke-nøkler i en tabell er avhengig av hele nøkkelen, og ikke bare deler av den, og at tabellen er på første normalform. Tredje normalform krever at alle data i en tabell ikke er avhengig av data som ikke er en del av en nøkkel. Om du normaliserer dine data før du tar lager databasekode, vil du spare mye tid og gjøre datasettet ditt enklere å behandle.
Shellscripting I. Innhold
Avdeling for informatikk og e-læring, Høgskolen i Sør-Trøndelag Shellscripting I Tor Halsan 19.08.2010 Lærestoffet er utviklet for faget LN199D Scripting av Servere Resymé: Leksjonen er første innføring
13.09.2012 LITT OM OPPLEGGET. INF1000 EKSTRATILBUD Stoff fra uke 1-3 12. September 2012 Siri Moe Jensen EKSEMPLER
.9.22 LITT OM OPPLEGGET INF EKSTRATILBUD Stoff fra uke - 2. September 22 Siri Moe Jensen Målgruppe: De som mangler forståelse for konseptene gjennomgått så langt. Trening får du ved å jobbe med oppgaver,
<?php. count tar en array som argument, og returnerer et tall som uttrykker antallet innførsler i arrayen.
Hver gang funksjonen printhallo kalles utføres instruksjonene spesifisert i den. [Kurssidene] [ ABI - fagsider bibin ] Webprogrammering høsten 2015 //funksjonskall printhallo(); //enda en gang printhallo();
Kanter, kanter, mange mangekanter
Kanter, kanter, mange mangekanter Nybegynner Processing PDF Introduksjon: Her skal vi se på litt mer avansert opptegning og bevegelse. Vi skal ta utgangspunkt i oppgaven om den sprettende ballen, men bytte
while-økker while-løkker gjentar instruksjonene så lenge en betingelse er oppfylt Eksempel 1: en enkel while-løkke
[Kurssidene] [ ABI - fagsider bibin ] Utvikling av dynamiske nettsteder med PHP og databaser, våren 2014 while-økker while-løkker gjentar instruksjonene så lenge en betingelse er oppfylt Michael Preminger
Introduksjon til beslutningsstrukturer
[Kurssidene] [ ABI - fagsider bibin ] Utvikling av dynamiske nettsteder med PHP og databaser, våren 2014 Introduksjon til beslutningsstrukturer Michael Preminger ([email protected]) 24/01-14 Repitisjon fra
Oblig 5 Webutvikling. Av Thomas Gitlevaag
Oblig 5 Webutvikling Av Thomas Gitlevaag For oppgave 1 og 2 skal dere levere en funksjonell webside på deres hjemmeområde. Dere skal også levere alle phps-filene slik at man for en hver side kan slenge
I denne oppgaven blir du introdusert for programmeringsspråket JavaScript. Du skal gjøre den klassiske oppgaven Hei verden, med en katt.
Hei JavaScript! Introduksjon Web Introduksjon I denne oppgaven blir du introdusert for programmeringsspråket JavaScript. Du skal gjøre den klassiske oppgaven Hei verden, med en katt. Steg 1: Bruke JS Bin
INF109 - Uke 1b 20.01.2016
INF109 - Uke 1b 20.01.2016 1 Variabler Et program er ikke til stor hjelp hvis det er statisk. Statisk betyr at programmet bare bearbeider faste data som er lagt inn i programkoden. For å gjøre programmer
Verdier, variabler og forms
[Kurssidene] [ ABI - fagsider bibin ] Verdier, variabler og forms Michael Preminger ([email protected]) 16/01-14 Utvikling av dynamiske nettsteder med PHP og databaser, våren 2014 Litt om forrige times øvelsesoppgaver
[Kurssidene] [ ABI - fagsider bibin ] Michael Preminger ([email protected]) 07/09-15. Vi holder orden på verdier med hjelp av variabler
[Kurssidene] [ ABI - fagsider bibin ] Michael Preminger ([email protected]) 07/09-15 Vi holder orden på verdier med hjelp av variabler Vi lagrer verdier i variabler. Variabelnavn uttrykker verdienes rolle
Del 1: Overgang fra gammel hjemmeside til ny hjemmeside
Del 1: Overgang fra gammel hjemmeside til ny hjemmeside Instituttsider og personlige hjemmesider som ligger på HFs egen webserver skal nå fases ut.dette innebærer at alle som fortsatt har hjemmesider der,
TDT4102 Prosedyre og Objektorientert programmering Vår 2014
Norges teknisk naturvitenskapelige universitet Institutt for datateknikk og informasjonsvitenskap TDT4102 Prosedyre og Objektorientert programmering Vår 2014 Øving 10 Frist: 2014-04-11 Mål for denne øvinga:
Oblig 4 (av 4) INF1000, høsten 2012 Værdata, leveres innen 9. nov. kl. 23.59
Oblig 4 (av 4) INF1000, høsten 2012 Værdata, leveres innen 9. nov. kl. 23.59 Formål Formålet med denne oppgaven er å gi trening i hele pensum og i å lage et større program. Løsningen du lager skal være
JSP - 2. Fra sist. Hvordan fungerer web? Tjenerside script HTML. Installasjon av Web-tjener Et enkelt JSP-script. Ønsker dynamiske nettsider:
Fra sist JSP - 2 Installasjon av Web-tjener Et enkelt JSP-script HTML statisk Forms Tags Ønsker dynamiske nettsider: Klientside-script/programmering Javascript, vbscript, applets Tjenerside-script/programmering
HØGSKOLEN I SØR-TRØNDELAG
HØGSKOLEN I SØR-TRØNDELAG Avdeling for informatikk og e-læring - AITeL Kandidatnr: Eksamensdato: 15. desember 2004 Varighet: Fagnummer: Fagnavn: Klasse(r): 3 timer LV197D Webprogrammering med PHP FU Studiepoeng:
datatyper Hva er programmering? Variabler og Informasjonsteknologi 2 Kompetansesemål
Variabler og datatyper Gløer Olav Langslet Sandvika VGS Høst 2012 Informasjonsteknologi 2 Hva er programmering? Når du skal bake en kake følger du gjerne en oppskrift. Først er det beskrevet hva kaken
HTML og relasjonsdatabaser med PHP
HTML og relasjonsdatabaser med PHP Oppgaveveiledning Kent Dahl Informasjonsbehandling Brukersystemer Orkdal videregående skole (7. mars 2004) Innholdsfortegnelse 1. Introduksjon...2 1.1.
Innstallasjon og oppsett av Wordpress
Del 1 - Installasjon og oppsett Innstallasjon og oppsett av Wordpress Wordpress har blitt en veldig populær publiseringsplattform for websider. Uten særlige tekniske ferdigheter kan man sette opp profesjonelle
Øving 0 - Xcode TDT4102
Øving 0 - Xcode TDT4102 Frivillig Øving Mål for denne øvingen: Bli kjent med programmeringsverktøy Lage et første program kun med teksteditor og kompilator Lage et første program med Xcode Denne øvingen
Brukerveiledning http://www.hovikif.no/ Bruk av siden. Når du går inn på siden får du opp følgende bilde:
Brukerveiledning http://www.hovikif.no/ Bruk av siden Når du går inn på siden får du opp følgende bilde: Øverst i høyre hjørne kan du endre størrelsen på teksten og søke etter lagrede artikler. De enkelte
som blanker skjermen (clear screen). Du får en oversikt over alle kommandoene ved å skrive,
1. Last ned og installer XAMPP. 2. Sjekk at alt fungerer. 3. MySQL. Vi begynner med databaseserveren, MySQL. Gå til DOS klarmelding eller ledetekst (finnes under tilbehør på startmenyen om du ikke som
if-tester Funksjoner, løkker og iftester Løkker og Informasjonsteknologi 2 Læreplansmål Gløer Olav Langslet Sandvika VGS
Løkker og if-tester Gløer Olav Langslet Sandvika VGS 29.08.2011 Informasjonsteknologi 2 Funksjoner, løkker og iftester Læreplansmål Eleven skal kunne programmere med enkle og indekserte variabler eller
TDT4102 Prosedyreog objektorientert programmering Vår 2016
Norges teknisk naturvitenskapelige universitet Institutt for datateknikk og informasjonsvitenskap TDT4102 Prosedyreog objektorientert programmering Vår 2016 Øving 4 Frist: 2016-02-12 Mål for denne øvingen:
Installere JBuilder Foundation i Windows XP
Installere JBuilder Foundation i Windows XP Installasjon av JBuilder Foundation på Windows (dekker her spesifikt fremgangen ved bruk av Microsoft Windows XP Professional, men det vil mest trolig ikke være
Programmeringsspråk for nybegynnere. Krav til språket. Krav til språket. Krav til språket
Programmeringsspråk for nybegynnere Krav til språket Hva om vi laget vårt eget språk til INF1000? Programmeringsspråket må være så enkelt som mulig. (Programmering er vanskelig nok som det er.) Hvilke
Dokumentasjon av Installasjon
Vedlegg D Dokumentasjon av Installasjon Dette dokumentet tar for seg detaljert informasjon vedrørende installasjon nødvendig for delapplikasjonene i PySniff. Innholdsfortegnelse 1. INTRODUKSJON 3 2. PYTHON
TDT4110 Informasjonsteknologi, grunnkurs Uke 35 Introduksjon til programmering i Python
TDT4110 Informasjonsteknologi, grunnkurs Uke 35 Introduksjon til programmering i Python Professor Guttorm Sindre Institutt for datateknikk og informasjonsvitenskap Læringsmål og pensum Mål Vite hva et
CASCADING STYLESHEETS (CSS)
CASCADING STYLESHEETS (CSS) HVA ER CSS Stylesheets er en metode for å flytte selve formatteringen av et HTML dokument ut av selve dokumentet og over i et eksternt regelsett. Dette skyldes HTMLs manglende
praktiske eksempler DOM Document Object Model DOM og Høst 2013 Informasjonsteknologi 2 Læreplansmål Gløer Olav Langslet Sandvika VGS
DOM og praktiske eksempler Gløer Olav Langslet Sandvika VGS Høst 2013 Informasjonsteknologi 2 DOM Document Object Model Læreplansmål Eleven skal kunne programmere med enkle og indekserte variabler eller
Tre måter å lese fra terminal. Java 4. Eksempel. Formatert utskrift til skjerm
Mer om easyio Mer om forgreninger Løkker 7. september 2004 Ole Christian Lingjærde Gruppen for bioinformatikk Institutt for informatikk Universitetet i Oslo Java 4 1 Tre måter å lese fra terminal Først:
Kapittel 1. Datamaskiner og programmeringsspråk. 1.1 Programmering
Kapittel 1 Datamaskiner og programmeringsspråk Dette kapitlet er en kort introduksjon til programmering. Vi vil se på hvordan man skriver, bygger og kjører programmer, samt illustrere noen sentrale programmeringsbegrep
EKSAMEN. Les gjennom alle oppgavene før du begynner. Husk at det ikke er gitt at oppgavene står sortert etter økende vanskelighetsgrad.
EKSAMEN Emnekode: Emne: ITF10208 Webprogrammering 1 Dato: Eksamenstid: 09/12-2008 09.00-13.00 Hjelpemidler: 2 A4 ark (4 sider) med egenproduserte notater (håndskrevne/maskinskrevne) Faglærer: Tom Heine
4. Installasjonsveiledning. Experior - rich test editor for FitNesse -
4. Experior - rich test editor for FitNesse - 4.1. Forord Denne rapporten inneholder installasjonsveiledning for Experior. Experior er tilpasset for installasjon i oppdragsgivers utviklingsmiljø. Det er
Høst 2014. Øving 5. 1 Teori. 2 Månedskalender. Norges teknisknaturvitenskapelige universitet Institutt for datateknikk og informasjonsvitenskap
TDT4105 IT Grunnkurs Høst 2014 Norges teknisknaturvitenskapelige universitet Institutt for datateknikk og informasjonsvitenskap Øving 5 1 Teori a) Hva er den binære ASCII-verdien av bokstaven E (stor e)?
Asteroids. Oversikt over prosjektet. Steg 1: Enda et flyvende romskip. Plan. Sjekkliste. Introduksjon
Asteroids Ekspert Scratch Introduksjon På slutten av 1970-tallet ga Atari ut to spill hvor man skulle kontrollere et romskip. Det første var Lunar Lander, men dette ble utkonkurrert av Asteroids som Atari
PixEdit Guide MEDFAK (5. utkast)
PixEdit Guide MEDFAK (5. utkast) Dette er en kjapp guide på hvordan vi har gjort PixEdit-oppsettet på arkivet ved MEDFAK. Denne guiden tar utgangspunkt i en dedikert kontormaskin med lokal skanner. Med
TDT4102 Prosedyreog objektorientert programmering Vår 2016
Norges teknisk naturvitenskapelige universitet Institutt for datateknikk og informasjonsvitenskap TDT4102 Prosedyreog objektorientert programmering Vår 2016 Øving 0 for Mac Frist: Ingen (frivillig øving)
Steg for steg. Sånn tar du backup av Macen din
Steg for steg Sånn tar du backup av Macen din «Being too busy to worry about backup is like being too busy driving a car to put on a seatbelt.» For de fleste fungerer Macen som et arkiv, fullt av bilder,
WP-WATCHER WORDPRESS SIKKERHET
WP-WATCHER WORDPRESS SIKKERHET WP-WATCHER BACKUP - SIKKERHETSKOPIERING «Hei! Jeg oppdaterte en plugin på siden min og nå kommer jeg ikke inn på siden min i det hele tatt. Kan du hjelpe meg?» «Hjelp! Jeg
Utførelse av programmer, metoder og synlighet av variabler i JSP
Utførelse av programmer, metoder og synlighet av variabler i JSP Av Alf Inge Wang 1. Utførelse av programmer Et dataprogram består oftest av en rekke programlinjer som gir instruksjoner til datamaskinen
Hvordan installere Java og easyio på Windows
Hvordan installere Java og easyio på Windows Denne veiledningen forklarer en enkel måte å installere Java og easyio på din egen Windows-datamaskin. Du kan finne veiledninger for andre operativsystemer
Administrering av SafariSøk
Administrering av SafariSøk Administrering av SafariSøk Revisjonshistorie Revisjon $Revision: 1.6 $ $Date: 2003/08/05 12:44:02 $ Innholdsfortegnelse 1. Om programmet... 1 Generelt... 1 2. Fremgangsmåter...
Kjøre Wordpress på OSX
Kjøre Wordpress på OSX Alt etter hva du ønsker å bruke Webserveren til er det flere måter å gjøre dette på. Ønsker du kun en side som skal dele sider du lager manuelt, med PHP, GD etc eller med server
TDT4102 Prosedyre og Objektorientert programmering Vår 2014
Norges teknisk naturvitenskapelige universitet Institutt for datateknikk og informasjonsvitenskap TDT4102 Prosedyre og Objektorientert programmering Vår 2014 Øving 1 Frist: 2014-01-24 Mål for denne øvinga:
Enarmet banditt Nybegynner Scratch Lærerveiledning
Enarmet banditt Nybegynner Scratch Lærerveiledning Introduksjon Dette er et spill med tre figurer som endrer utseende. Din oppgave er å stoppe figurene én etter én, slik at alle tre blir like. Steg 1:
INF1000 Metoder. Marit Nybakken [email protected] 16. februar 2004
INF1000 Metoder Marit Nybakken [email protected] 16. februar 2004 Motivasjon Når man begynner å skrive store programmer, vil man fort oppleve at programmene blir uoversiktlige. Det blir vanskeligere
Øvingsforelesning i Python (TDT4110)
Øvingsforelesning i Python (TDT4110) Tema: Øving 1, PyCharm, Print, Input, (funksjoner og globale variabler) Gå til https://www.jetbrains.com/pycharm/ og sett PyCharm på nedlasting NÅ Kristoffer Hagen
Telle i kor steg på 120 frå 120
Telle i kor steg på 120 frå 120 Erfaringer fra utprøving Erfaringene som er beskrevet i det følgende er gjort med lærere og elever som gjennomfører denne typen aktivitet for første gang. Det var fire erfarne
Lynkurs i shellprogrammering under Linux
Lynkurs i shellprogrammering under Linux Interaktiv bruk av shell Shell/skall er en applikasjon som lar bruker taste inn tekstlige kommandoer til Linux en og en linje om gangen (leser linjer fra stdin).
notater Gule lapper Mine Et praktisk eksempel med objekter IT2 Læreplansmål Gløer Olav Langslet Sandvika VGS
Mine notater Gløer Olav Langslet Sandvika VGS Et praktisk eksempel med objekter Vi kjenner alle til korktavlen med gule lapper. Vi henger opp en lapp for at vi selv eller andre skal huske eller bli minnet
La oss gjøre nettsiden vår bedre med noen stiler. I denne og den neste leksjonen skal vi lære hvordan man endrer farge, tekst, størrelser og mer!
Lesson 4 CSS All Code Clubs must be registered. Registered clubs appear on the map at codeclub.org.uk - if your club is not on the map then visit jumpto.cc/18cplpy to find out what to do. Introduksjon
Hemmelige koder. Kodeklubb-koden. Steg 1: Alfabetet. Sjekkliste. Introduksjon
Hemmelige koder Nybegynner Python Introduksjon Legg bort skilpaddene dine, i dag skal vi lære hvordan vi kan sende hemmelige beskjeder! Kodeklubb-koden Et chiffer er et system for å gjøre om vanlig tekst
Del 1 En oversikt over C-programmering
Del 1 En oversikt over C-programmering 1 RR 2016 Starten C ble utviklet mellom 1969 og 1973 for å re-implementere Unix operativsystemet. Er et strukturert programmeringsspråk, hvor program bygges opp av
Matematikk 1000. Øvingeoppgaver i numerikk leksjon 1 Å komme i gang
Matematikk 1000 Øvingeoppgaver i numerikk leksjon 1 Å komme i gang I denne øvinga skal vi bli litt kjent med MATLAB. Vi skal ikkje gjøre noen avanserte ting i dette oppgavesettet bare få et visst innblikk
POLITISKE SAKSDOKUMENTER:
POLITISKE SAKSDOKUMENTER: FRA PAPIR TIL PC Installasjons- og brukerveiledning Sunndal kommune Side 1 of 20 Side 2 of 20 Innholdsfortegnelse 1 Laste ned PDF-XChange Viewer...5 2 Installere PDF-XChange Viewer...6
!!!!!!!!!!!! !!!!!!!!!!! WP-WATCHER WORDPRESS SIKKERHET
WP-WATCHER WORDPRESS SIKKERHET WP-WATCHER BACKUP - SIKKERHETSKOPIERING «Hei Jeg oppdaterte en plugin på siden min og nå kommer jeg ikke inn på siden min i det hele tatt. Kan du hjelpe meg?» «Hjelp Jeg
Straffespark Introduksjon Scratch Lærerveiledning
Straffespark Introduksjon Scratch Lærerveiledning Introduksjon Vi skal lage et enkelt fotballspill, hvor du skal prøve å score på så mange straffespark som mulig. Steg 1: Katten og fotballbanen Vi begynner
www.mentalhelse.no Vårt nettsted En håndbok for lokale nettredaktører i fylkes- og lokallag
www.mentalhelse.no Vårt nettsted En håndbok for lokale nettredaktører i fylkes- og lokallag Introduksjon Gratulerer Mental Helse! Våre nettsider har fått en oppfriskning og fremstår i ny drakt. Design
1. Programmering: Hva og hvorfor? Scratch fra scratch Enkel programmering for nybegynnere
1. Programmering: Hva og hvorfor? 1. Programmering: Hva og hvorfor? Du har nå valgt å lære deg å programmere. Gratulerer med et flott valg! Programmering er en allsidig og nyttig aktivitet, og det er et
Dagens tema: 12 gode råd for en kompilatorskriver. Sjekking av navn. Lagring av navn. Hvordan finne et navn?
Dagens tema: 12 gode råd for en kompilatorskriver Hva skal gjøres med navn? Sjekking av navn Hvordan sjekke navn? Testutskrifter 12 gode råd En kompilator må også sjekke riktig navnebruk: Det må ikke forekomme
Mamut. Installasjonsveiledning. Oppdatering til versjon 12.1. Detaljert steg-for-steg veiledning i hvordan oppdatere ditt datax-program fra Mamut
Mamut Installasjonsveiledning Oppdatering til versjon 12.1 Detaljert steg-for-steg veiledning i hvordan oppdatere ditt datax-program fra Mamut 2 sjekkliste OPPDAteRiNG AV Ditt system Sjekkliste før du
I denne oppgaven blir du introdusert for programmeringsspråket JavaScript. Du skal gjøre den klassiske oppgaven Hei verden, med en katt.
JS: Hei JavaScript! Skrevet av: Arve Seljebu Kurs: Web Tema: Tekstbasert, Nettside Fag: Programmering Klassetrinn: 8.-10. klasse, Videregående skole Introduksjon I denne oppgaven blir du introdusert for
Overgang til RT4 hjelp for saksbehandlere
Overgang til RT4 hjelp for saksbehandlere I forbindelse med oppgradering av RT fra versjon 3.8 til 4, vil man kunne oppleve at menyer og funksjonalitet har endret seg noe. Dette dokumentet tar for seg
TDT4102 Prosedyre og Objektorientert programmering Vår 2014
Norges teknisk naturvitenskapelige universitet Institutt for datateknikk og informasjonsvitenskap TDT4102 Prosedyre og Objektorientert programmering Vår 2014 Øving 1 Frist: DD.MM.YYYY Mål for denne øvinga:
DVD-Kopiering v. 1.1
DVD-Kopiering v. 1.1 For sikkerhetskopiering av dine DVDer Mac OS X Denne manualen vil vise deg hvordan du kan kopiere en DVD over på maskinen din, for så å brenne den på en tom DVD±R(W)-plate. Det skal
Du har sikkert allerede startet noen programmer ved å trykke på kontrollknappen. VINDUER = WINDOWS
Operativsystemet Kort historie Utviklingen av datamaskiner og dataprogrammer går fort. Den som har sitt første møte med dataverdenen i dette kurset, vil kanskje allikevel ha hørt om DOS (Disk Operating
Kom i gang med Python
Kom i gang med Python Instruksjon for lærere Pål Hellesnes SYSTEMUTVIKLER [email protected] www.bedreinnsikt.no Dette dokumentet er en del av skolematerialet for undervisning i programmering. «Alle barn
Web fundamentals. Web design. Frontend vs. Backend 17.01.2008. Webdesign 17. januar 2008 3. Monica Strand
Web fundamentals Webdesign 17. januar 2008 Monica Strand Webdesign 17. januar 2008 1 Web design Fagområdet Web design inneholder flere disipliner Grafisk design Informasjonsdesign Brukergrensesnittdesign
Ordliste. Obligatorisk oppgave 1 - Inf 1020
Ordliste. Obligatorisk oppgave 1 - Inf 1020 I denne oppgaven skal vi tenke oss at vi vil holde et register over alle norske ord (med alle bøyninger), og at vi skal lage operasjoner som kan brukes til f.
I denne oppgaven blir du introdusert for programmeringsspråket JavaScript. Du skal gjøre den klassiske oppgaven Hei verden, med en katt.
JS: Hei JavaScript! Introduksjon Web Introduksjon I denne oppgaven blir du introdusert for programmeringsspråket JavaScript. Du skal gjøre den klassiske oppgaven Hei verden, med en katt. Steg 1: Bruke
Husk at du skal ha to vinduer åpne. Det ene er 'Python Shell' og det andre er for å skrive kode i.
Skilpaddeskolen Steg 1: Flere firkanter Nybegynner Python Åpne IDLE-editoren, og åpne en ny fil ved å trykke File > New File, og la oss begynne. Husk at du skal ha to vinduer åpne. Det ene er 'Python Shell'
PBL Barnehageweb. Brukerveiledning
PBL Barnehageweb Brukerveiledning 1 1. Innledning Gratulerer med valget av nye PBL Barnehageweb! Med PBL Barnehageweb skal det være enkelt å lage en brukervennlig, moderne og profesjonell nettside for
Soloball. Steg 1: En roterende katt. Sjekkliste. Test prosjektet. Introduksjon. Vi begynner med å se på hvordan vi kan få kattefiguren til å rotere.
Soloball Introduksjon Scratch Introduksjon Vi skal nå lære hvordan vi kan lage et enkelt ballspill med Scratch. I soloball skal du styre katten som kontrollerer ballen, slik at ballen ikke går i nettet.
Utførelse av programmer, funksjoner og synlighet av variabler (Matl.)
Utførelse av programmer, funksjoner og synlighet av variabler (Matl.) Av Jo Skjermo (basert på Alf Inge Wang sin versjon om JSP). 1. Utførelse av kode i kommando/kalkulatormodus Et dataprogram består oftest
INF130 Datahåndtering og analyse
INF130 Datahåndtering og analyse Visualisering av data på web Applikasjonsutvikling Applikasjonsutvikling mot web Databaseapplikasjoner Informasjonssystemer Arkitektur PHP = PHP Hypertext Processor PHP
23.09.2015. Introduksjon til objektorientert. programmering. Hva skjedde ~1967? Lokale (og globale) helter. Grunnkurs i objektorientert.
Grunnkurs i objektorientert programmering Introduksjon til objektorientert programmering INF1000 Høst 2015 Siri Moe Jensen INF1000 - Høst 2015 uke 5 1 Siri Moe Jensen INF1000 - Høst 2015 uke 5 2 Kristen
3. Kravspesifikasjon. Experior - rich test editor for FitNesse -
3. Experior - rich test editor for FitNesse - 3.1. Forord Dette dokumentet inneholder krav til funksjonalitet i Experior og hvordan denne skal integreres inn i selve FitNesse. I tillegg spesifiseres krav
Installere JBuilder Foundation i Mandrake Linux 10.0
Installere JBuilder Foundation i Mandrake Linux 10.0 Installasjon av JBuilder Foundation på Linux (dekker her spesifikt fremgangen ved bruk av Mandrake Linux 10.0, men distribusjon vil gjøre liten eller
Gangemesteren Nybegynner Scratch PDF
Gangemesteren Nybegynner Scratch PDF Introduksjon I dag skal vi lage et nyttig spill, nemlig et spill som hjelper oss å lære andre ting. Vi skal få hjelp til å lære gangetabellen! Steg 1: Læremesteren
Leksjon 3. Kontrollstrukturer
6108 Programmering i Java Leksjon 3 Kontrollstrukturer Del 2 Løkker Roy M. Istad 2015 Utførelse av et program Programflyt så langt start setning setning setning setning Sekvensielt Alle setninger utføres,
Testrapport Prosjekt nr. 2011-22 Det Norske Veritas
Prosjekt nr. 2011 22 Testrapport Hovedprosjektets tittel Implementering av plugin og utvikling av wizard for Det Norske Veritas Prosjektdeltakere Magnus Strand Nekstad s156159 Jørgen Rønbeck s135779 Dato
Behandling av dokumenter i Microsoft Word. En rask innføring
Behandling av dokumenter i Microsoft Word En rask innføring Forord Denne guiden er utformet av Orakeltjenesten ved Dragvoll som en enkel innføring i grunnleggende funksjoner i Word for å hjelpe studenter
(X)HTML, CSS og JavaScript HTML. Det første dokumentet 26.11.2007. Grunnleggende programmering i Java Monica Strand 26.
(X)HTML, CSS og JavaScript Grunnleggende programmering i Java Monica Strand 26. november 2007 Gr. leggende Java 26. november 2007 1 HTML HTML = Hyper Text Markup Language Strukturerer tekstinnhold HTML
TDT4102 Prosedyreog objektorientert programmering Vår 2016
Norges teknisk naturvitenskapelige universitet Institutt for datateknikk og informasjonsvitenskap TDT4102 Prosedyreog objektorientert programmering Vår 2016 Øving 5 Frist: 2016-02-19 Mål for denne øvingen:
Posisjonsystemet FRA A TIL Å
Posisjonsystemet FRA A TIL Å VEILEDER FOR FORELDRE MED BARN I 5. 7. KLASSE EMNER Side 1 Innledning til posisjonsystemet P - 2 2 Grunnleggende om posisjonsystemet P - 2 3 Titallsystemet P - 3 4 Posisjonsystemet
Læringsmål og pensum. https://www.youtube.com/watch? v=nkiu9yen5nc
1 TDT4110 Informasjonsteknologi grunnkurs: Kapittel 1 Introduksjon til Programmering og Python Professor Alf Inge Wang 2 https://www.youtube.com/watch? v=nkiu9yen5nc 3 Læringsmål og pensum Mål Lære om
Øvingsforelesning 1 Python (TDT4110)
Øvingsforelesning 1 Python (TDT4110) Introduksjon, Kalkulasjoner Ole-Magnus Pedersen Oversikt Praktisk Info Repetisjon fra sist Oppgaver for øving 2 2 Praktisk Info Last opp øvinger på Blackboard før godkjenning
Kjernejournal. Pilotering - Javafri oppkobling
Kjernejournal Pilotering - Javafri oppkobling 07-01-2016 Kolofon Publikasjonens tittel: Tilrettelegging mot kjernejournal med Commfides Utgitt: 16.03.16 Publikasjonsnummer: Utgitt av: Direktoratet for
En liten oppskrift på hvordan jeg installert og fikk Xastir til å virke sånn at jeg ble synlig i APRS verden.
En liten oppskrift på hvordan jeg installert og fikk Xastir til å virke sånn at jeg ble synlig i APRS verden. La meg med en gang si at jeg er rimelig grønn i Linux verden så dere får bære over med meg
Kapittel 1. Kom i gang med PHP
Kapittel 1 Kom i gang med PHP Læringsmål: Dette kapittelet vil fungere som en enkel oppstartsguide for å komme i gang med PHP. Du vil få lære om historien bak PHP installasjon av nødvendig programvare
Bygg et Hus. Steg 1: Prøv selv først. Sjekkliste. Introduksjon. Prøv selv
Bygg et Hus Introduksjon I denne leksjonen vil vi se litt på hvordan vi kan få en robot til å bygge et hus for oss. Underveis vil vi lære hvordan vi kan bruke løkker og funksjoner for å gjenta ting som
Memoz brukerveiledning
Memoz brukerveiledning http://memoz.hib.no Pålogging...1 Oversikt...2 Profilside...2 Inne i en memoz...3 Legg til ting...3 Tekstboks...3 Rediger og flytte på en boks...4 Bildeboks...5 Videoboks...7 HTML-boks...7
Veileder i bruk av GoodReader
RISØR KOMMUNE Veileder i bruk av GoodReader Innhold 1. Laste ned dokument fra kommunens hjemmeside til GoodReader... 2 2. Bruke GoodReader... 7 3. Redigere filnavn... 8 4. Opprette kataloger / mapper...
Komme i gang med Skoleportalen
Generell brukerveiledning for Elevportalen Denne elevportalen er best egnet i nettleseren Internett Explorer. Dersom du opplever kompatibilitets-problemer kan det skyldes at du bruker en annen nettleser.
INF 4130. 8. oktober 2009. Dagens tema: Uavgjørbarhet. Neste uke: NP-kompletthet
INF 4130 8. oktober 2009 Stein Krogdahl Dagens tema: Uavgjørbarhet Dette har blitt framstilt litt annerledes tidligere år Se Dinos forelesninger fra i fjor. I år: Vi tenker mer i programmer enn i Turing-maskiner
Velkommen som ny bruker av Uni Økonomi!
Velkommen som ny bruker av Uni Økonomi! Som ny kunde har du fått tilsendt tilsendt epost som vist under, hvor du starter installasjonen av Uni Økonomi - ved å klikke på lenken som står etter "Gå til:"
SMART hus via nettleseren
itoginnovasjon.no.217.171.192.197.xip.io http://www.itoginnovasjon.no.217.171.192.197.xip.io/wikis/smart-hus-via-nettleseren/ SMART hus via nettleseren SMART hus via nettleseren: Det vi har gjort nå er
