Guide: PHP- & MySQL-innføring: 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.

Side 1: Introduksjon

Alternativ tekst mangler
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å.

Her er de tidligere kapitlene i vår gjennomgang;

Side 2: Basiskunnskaper

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, 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 GET-syntaks.

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;

<?php
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.

Side 3: Sikkerhet

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.

<?php
$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);
?>

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.

<?php
$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 = \"http://www.hardware.no/\";</script>";
$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);

<b>Vegard</b> er <em>kul!</em> -> Vegard er kul!
<script type="text/javascript">windows.location = 
    "http://www.hardware.no/";</script> 
-> windows.location = "http://www.hardware.no/";
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 &lt& og &aring; (å). 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);

<?php
$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 = \"http://www.hardware.no/\";</script>";
$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> -> 
  &lt;b&gt;Vegard&lt;/b&gt; er &lt;em&gt;kul!&lt;/em&gt;
<script type="text/javascript">windows.location = 
    "http://www.hardware.no/";</script> -> 
  &lt;script type=&quot;text/javascript&quot;&gt;windows.location = 
    &quot;http://www.hardware.no/&quot;;&lt;/script&gt;
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.

Side 4: Regulære uttrykk

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/Perl-kompatible funksjonene 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, 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.

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;

<?php
$nummer
[] = "12345678";
$nummer[] = "81000100";
$nummer[] = "+44 0230 2012 9021";
$nummer[] = "12 34 56 78";

// matcher strenger som kun inneholder et 8-sifret tall
$regex "/^\d{8}$/";

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.

12345678: 1
81000100: 1
+44 0230 2012 9021: 0
12 34 56 78: 0

Uttrykket vi bruker her; /^\d{8}$/, 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 = "/^(\d{2} ?){3}\d{2}$/";

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 "810 00 100", 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;

<?php
$nummer
[] = "12345678";
$nummer[] = "81000100";
$nummer[] = "+44 0230 2012 9021";
$nummer[] = "12 34 56 78";

// matcher strenger som kun inneholder et 8-sifret tall
$regexFjern "/\s*/";
$regexMatch "/^\d{8}$/";

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;

12345678 (redusert til 12345678): 1
81000100 (redusert til 81000100): 1
+44 0230 2012 9021 (redusert til +44023020129021): 0
12 34 56 78 (redusert til 12345678): 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.

<?php
$nummer
[] = "12345678";
$nummer[] = "81000100";
$nummer[] = "+44 0230 2012 9021";
$nummer[] = "+1 800 234 1234";
$nummer[] = "001 800 234 1234";
$nummer[] = "12 34 56 78";
$nummer[] = "Vegard";

// matcher strenger som kun inneholder et 8-sifret tall
$regexFjern "/\s*/";
$regexMatch "/^((\+|00)(\d{1,3}))?\d{5,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;

((\+|00)(\d{1,3}))? sier at vi kan begynne med en sekvens som består av + eller 00, etterfulgt av et til tre siffer. \d{5,12} sier at her må det være mellom fem og tolv tall i rekkefølge. Resultatet fra skriptet blir;

12345678 (redusert til 12345678): 1
81000100 (redusert til 81000100): 1
+44 0230 2012 9021 (redusert til +44023020129021): 1
+1 800 234 1234 (redusert til +18002341234): 1
001 800 234 1234 (redusert til 0018002341234): 1
12 34 56 78 (redusert til 12345678): 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) 12 34 56 68", 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 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_email($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);
}
?>

Side 5: Feilmeldinger

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;

<?php
$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="<?php 
          
echo $fornavn;
          
?>" />
  </p>
<?php
    
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="<?php 
          
echo $etternavn;
          
?>"/>
  </p>
<?php
    
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>
<?php
}
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 HTML-kode, men man ser også hvor fort det blir rotete.

På et senere tidspunkt i denne artikkelserien kommer vi til å gå gjennom såkalte template-systemer, som lar deg skrive mye ryddigere kode.

Side 6: Ta imot arrays

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;

<form method="POST" action="6-13.php">
<?php
    $array 
$_REQUEST['array'];
    for (
$nr 1$nr 10$nr++)
    {
?>
  <p>Felt <?php echo $nr?>
      <input type="text" 
          name="array[<?php echo $nr?>]" 
          value="<?php
    
if ($array[$nr]) 
        echo 
htmlentities(strip_tags(stripslashes($array[$nr])));
?>" />
    </p>
<?php
    
}
?>
  <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. PHP-skriptet 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">
<?php
    $array 
$_REQUEST['array'];
    for (
$nr 0$nr 10$nr++)
    {
?>
  <p>Felt <?php echo $nr?>
      <input type="text" 
          name="array[]" 
          value="<?php
    
if (isset($array[$nr])) 
        echo 
htmlentities(strip_tags(stripslashes($array[$nr])));
?>" />
    </p>
<?php
    
}
?>
  <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.

Side 7: POST, GET og REQUEST

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.

Du kan løse dette ved å benytte deg av variabler tilsvarende $_REQUEST for de ulike typene. GET-data 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å forumet, vil du se at adressen til PHP-forumet er

http://www.diskusjon.no/index.php?showforum=30

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;

http://www.diskusjon.no/index.php?act=Post&CODE=02&f=30&t=324727

Her er det fire variabler som blir satt; act, CODE, f og t, henholdsvis med verdiene Post, 02, 30 og 324727. 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.

Side 8: Ta imot filer

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 $_FILES-variabelen, 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):

Gitt at dette skjemaet har filnavnet 6-14.php, kan vi lagre følgende kode som 6-15.php og ha fungerende filopplasting.

<?php
// 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(010000000) . '.' $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 filopplasting ut.
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;



<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.

Side 9: Oppsummering

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å.


Alternativ tekst mangler
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.

Neste gang

I neste kapittel av denne gjennomgangen 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å.

Spørsmål, forslag og tilbakemeldinger til denne artikkelserien kan stilles i forumet.