Headers og PHP (cookies, sessions mm.)

Tags:    php
Skrevet af Bruger #3143 @ 04.01.2004
I denne artikel vil jeg beskrive nogle ting omkring HTTP headers, hvordan de virker, og hvordan de kan bruges. Jeg vil gennemgå nogle fejl i PHP, som jeg har erfaret, at mange laver, og forklare teorien bag. Det forudsættes at du i forvejen ved en lille smule om cookies og sessions.

Headers og HTTP


En kommunikation over HTTP forløber, simpelt skrevet, således:

En bruger klikker på et link på en webside. Herefter findes den server, hvor siden ligger på, og der skabes kontakt. Det vil jeg ikke komme nærmere ind på. Se eventuelt dk-hostmasters site (http://www.dk-hostmaster.dk/dkhostcms/bs?pageid=77&action=cmsview) omkring DNS. Når der er kontakt mellem de to servere, sendes et HTTP request. Requestet behandles af serveren, og der sendes et response tilbage til klienten.

Request


Et HTTP request indeholder for det første adressen på den side, man vil besøge. For det andet indeholder den en række headers. Disse headers kan fx være post-data, cookies og info om browseren.

Post
Hvis man har submittet en form, der bruger post-method, sendes indholdet af felterne i headersne. (Hvis der bruges get-method, sendes de som en del af adresselinjen (URL’en) ) I PHP lægges disse data ind i en array-variabel, som hedder $_POST.

Eksempel: Vi sender følgende form af sted ved at trykke på knappen "Gør noget":

Fold kodeboks ind/udKode 
Dataene fra denne form vil blive sendt af sted som request-headers, og PHP vil automatisk lave en variabel der ser sådan ud:

Fold kodeboks ind/udKode 
Læg mærke til, at det kun er den submitknap, som trykkes på, der sendes med.

Cookies
Udover post-variabler sendes også cookies med header-data. Det foregår på den måde, at din internetbrowser finder alle de cookies, som den URL, der requestes, har adgang til, og sætter dem ind som headers. Tænk dig derfor godt om, før du laver en cookie. Begræns antallet så meget som muligt, og lav dem så korte som muligt. Sørg for at afgrænse tiden og de sider, der har adgang til cookien, til hvad, der er nødvendigt. Jo flere cookies du laver, jo flere data skal der sendes med, hver gang en side loades. Så at gå i gang med at lave et par tusinde cookies er ikke nogen særlig god idé. :)

Cookies fra browseren vil i PHP blive lagt ind i variablen $_COOKIE fx:

Fold kodeboks ind/udKode 
Læg mærke til den sidste cookie.

Sessions
Med sessions kan man gemme forskellige variabler på serveren for hver bruger. Mere herom senere. For så at identificere brugerne, kan man gemme en cookie hos hver bruger med et id. Det er dette id, der kan ses i den sidste cookie i eksemplet ovenfor.

Andre data
Udover post og cookies sendes der også en række andre headers med en request. Jeg vil lige nævne en af dem, HTTP_USER_AGENT. Her sendes en række informationer omkring brugerens browser. Fx i min browser ser den således ud:

Fold kodeboks ind/udKode 
Der er også en lang række andre headers som denne, og de kan hentes i variablen $_SERVER. I denne variabel er der ikke kun headerdata, men også en række andre data. Her er et lille script til at se hvad den indeholder:

Fold kodeboks ind/udKode 

Response


Nu har vi kigget på HTTP requesten. Når der er sendt en request af sted, vil serveren behandle den, og i dette tilfælde vil PHP behandle vores side, før den sendes tilbage til webbrowseren i et HTTP response. Et response består først af response headers og derfter af en body, dit HTML dokument. Og her kommer det vigtige:

I et HTTP response sendes først headerinformation og derefter dit html-dokument.

Er man først begyndt at sende noget af body-sektionen, kan man ikke redigere headers eller tilføje nye.

I PHP sendes headers til browseren, første gang der udskrives noget body-kode. Det er fordi body-kode sendes til browseren, efterhånden om det genereres. Det er en god ting, hvis man har et meget tidskrevende script, og man så kan starte med at sende noget til browseren, så brugeren kan se, at der sker noget. Indtil headers sendes, kan du frit oprette, redigere og slette dem.

Cookies
De headers man oftest har brug for, er headers til at sætte cookies. De kan laves automatisk ved hjælp af funktionen setcookie.

Eksempel:

Fold kodeboks ind/udKode 
setcookie har 6 parametre. Det er kun nødvendigt at sætte det første. Som nævnt før er det en god ide at begrænse tiden, stien og domænet, til hvad der er brug for. Hvis tiden sættes til 0, vil cookien slettes når browseren lukkes. For at slette en cookie skal man lave en ny med samme informationer som den, man vil slette, og sætte sletningstidspunktet til en gang i fortiden. For mere information om setcookie, se PHP-manualen (http://dk.php.net/setcookie).

Cookies sættes altså i headers. Det er derfor ikke muligt at sætte flere cookies, når headers er sendt. Hvis man alligevel gør det, vil man få en fejlmeddelelse, der ligner:

Fold kodeboks ind/udKode 
Filen, der har fremkaldt denne fejl, ser således ud:

Fold kodeboks ind/udKode 
Det ser måske ikke ud som om, der er sendt noget kode til browseren, men der er allerede sendt to linjeskift !! Derfor kan du ikke sætte denne cookie.

Løsningen er at flytte setcookie op i starten af scriptet. Hvis det ikke er muligt, kan du bruge ob_start() og ob_flush(), som omtales senere.

Det kan godt være svært at se, hvor fejlen er, selvom det står i fejlmeddelelsen, at det er i linje 3 (i eksemplet). Det kan som i eksemplet være linjeskift eller mellemrum, det kan være tekst fra inkluderede filer, og det kan være tekst fra fejlmeddelelser, der er kommet tidligere.

Det er ikke sikkert, at browseren modtager cookien, og brugeren kan vælge at slette den. Du kan ikke se om cookien er sat. Hvis du kunne, skulle denne information sendes i requesten, og den er allerede blevet sendt, før PHP overhovedet er begyndt at udføre scriptet, så det kan man ikke.

Du kan heller ikke se din cookie, før næste gang siden loades, fordi cookies, der er gemt, sendes med requestet og variablen $_COOKIE sættes før scriptet køres. Du kan dog selv sætte værdien ind i variablen hver gang du bruger setcookie:

Fold kodeboks ind/udKode 
Du skal stadigvæk huske på, at en cookie ikke bliver sat ved at ændre i $_COOKIE variablen.

Sessions
Hvis du ikke ved hvad sessions er, er dette nok volapyk. Hvis du vil lære om sessions, kan du læse denne artikel. (http://udvikleren.dk/article.php?aid=87&techid=6)

Som tidligere nævnt bruger sessions cookies til at bestemme, hvilken bruger der besøger siden. Den gemmer et id i en cookie, når funktionen session_start() kaldes. Derfor er det vigtigt, at headers ikke er sendt lige som i cookies. Det er derfor altid en god idé at sætte denne funktion øverst i sit script. Husk også, at sessionen gælder for inkluderede sider, lige som alt andet. Du skal altså IKKE bruge session_start() igen i include-filer.

Lige gyldigt hvor mange filer på serveren, der inkluderes, sendes der kun et request og et response mellem serveren og klienten. Derfor skal session_start() kun bruges én gang.

Sessions bruges ofte til at lave login-systemer. Det er ofte mere sikkert end fx at gemme brugernavn og password i cookies. Dog betyder det, at alle, der besøger siden, vil få gemt en cookie. Det kan man forhindre ved at sætte session på følgende måde:

Fold kodeboks ind/udKode 
Her startes session kun, hvis der er logget ind. Man skal så huske at kalde session_start(), når der tjekkes for brugernavn og password.

Det kan man mene, er en ligegyldig detalje, især fordi session cookies ofte har levetiden 0, det vil sige, at den slettes, når browseren lukkes, men jeg har nu alligevel valgt at tage den med.

Andre headers
Der findes også en række andre headers. Disse kan ændres med funktionen header(). Du kan læse mere og funktionen og de forskellige headers i PHP-manualen. (http://dk.php.net/header) Her kan du også læse om headres, der bestemmer, hvordan sider skal cashes.

Location
Den mest brugte header, som skal sættes med header() funktionen er nok location. Denne header sender brugeren automatisk videre til en anden side. Det kan fx se således ud:

Fold kodeboks ind/udKode 
Location får browseren til at foretage et nyt request til den side, der er angivet. Den bruges ofte til at føre brugeren til en login-side, hvis brugeren besøger en beskyttet side uden at være logget ind.

Den bruges også nogen gange, til at tjekke om en cookie er blevet sat. Da der er sendt et response og et nyt request, skulle man mene, at cookien var sat. Det er dog ikke sikkert. Man kan ikke bestemme, hvilken rækkefølge headersne læses af browseren. Du ved derfor ikke, om din setcookie-header eller din location-header læses først. Derfor kan du risikere, at din cookie ikke er nået at blive sat, før den nye request sendes af sted.

Output buffering
Man skal som sagt sørge for at bruge header-funktionerne (setcookie, session_start og header), før man udskriver bare det mindste mellemrum til browseren. Er det ikke muligt, kan man bruge output buffering.

Det består først af funktionen ob_start(). Denne funktion sørger for, at alt, der udskrives til browseren, holdes tilbage, og derved at headers ikke sendes.

Når man har udført alle ændringer til headersne, kan man sende outputtet ved at bruge funktionen ob_flush(). Herved sendes headers også, og man kan ikke bruge setcookie(), session_start() og header() mere.

Det var så lidt om headers, og grunden til nogle af de fejlmeddelelser, man kan få når man bruger sessions og cookies. Håber det kan bruges.

Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (11)

User
Bruger #2397 @ 05.01.04 16:51
Velskrevet og velovervejet... Godt arbejde :o)
User
Bruger #3530 @ 05.01.04 16:53
Bravo
5 fra mig
User
Bruger #479 @ 05.01.04 19:23
Rart med en artikel omkring dette emne :) Der er rigtig mange nybegynder der ikke er så kendte med headers, så jeg tror det er godt med en artikel at henvise dem til.
5 herfra :D
User
Bruger #714 @ 06.01.04 21:32
god nok artikel, men hvad med lidt om hvordan den fil man egentlig sender ser ud? Altså bl.a. det med at i det browseren ser, der kommer der FØRST alle headerne, adskilt med linjeskift, og når headerne er sendt så kommer der 2 linjeskift og derefter kommer den egentlige fil, og mimetypen? Bør den ikke nævnes.

Og så ser jeg også at du bruger ob_flush(), hvorfor ikke ob_end_flush()? du skal da vel stoppe output bufferingen?

Elers god artikel, og et relevant emne, 4 herfra :-).
User
Bruger #4003 @ 08.01.04 15:05
God artikel, men som du selv skriver "Det forudsættes at du i forvejen ved en lille smule om cookies og sessions"....artiklen burde nok ikke være sat til "Niveau: Nybegynder", men det er jo en mindre detalje ;-)
User
Bruger #3143 @ 12.01.04 20:07
> god nok artikel, men hvad med lidt om hvordan den fil man egentlig sender ser ud?

Jeg ville ikke gøre artiklen for teoretisk, og så vidste jeg det heller ikke. (Ud over som skrevet, at headers sendes først)

> hvorfor ikke ob_end_flush()?

Det har du ret i. Jeg har aldrig selv brugt output buffering, så jeg fik ikke lige tænkt så meget over det.

> artiklen burde nok ikke være sat til "Niveau: Nybegynder"

Det synes jeg også selv...
User
Bruger #3752 @ 18.01.04 00:30
God artikel.. Jeg får helt lyst til at lave et brugersystem.
Forklaret så man forstår det - og alligevel også lærer noget.
5 herfra.
User
Bruger #5596 @ 16.04.04 08:36
Kanon artikel, den er virkelig velformuleret og lærerig indenfor området...
5 herfra.
User
Bruger #6731 @ 12.05.05 15:27
Dét skal jeg sgu huske!
User
Bruger #6686 @ 23.05.05 21:47
Har ikke læst artiklen, men før jeg læser den vil jeg lige vide. Hvad skal man bruge det til? (ikke for at være flabet :p) Mikl, en udvikler, har skrevet, at han mener man skal vide, hvad det skal bruges til, før man bevæger sig ud i det. Det kan jeg godt så pointen i. :)
Så var lige sød og skriv nogle ekspempler.
User
Bruger #14855 @ 24.06.09 12:15
Vil sige når du siger "cookie sessions mm" så når man skal starte på sessions så skriver du vis man ikke kan sessions så skal man læse en artikel (linket virker ikke)
Du skal være logget ind for at skrive en kommentar.
t