3. Moment03 - Formulär och datapersistens

Info

Till detta moment finns en sida med lösningsförslag

I detta moment skall vi börja kommunicera med användaren så att vi även får input att jobba med. Vi kommer lära oss att skapa formulär och ta emot det data som kommer den vägen, sedan skall vi titta på olika tekniker när det gäller datapersistens, alltså hur vi kan spara data på olika sätt så att vi kan använda data på flera sidor.

3.1 Formulär

Formulär är grunden till att kunna hämta in information från användaren. Du har stött på formulär så fort du matar in någon form av data till en webbsida, allt från det att du skapade ditt konto på facebook och fick ange information om dig, till att du gör en statusuppdatering eller loggar in som användare. Formulär är inte unikt för webben utan det krävs för input till alla typer av applikationer.

I detta avsnitt kommer jag gå igenom grunderna, det finns ett antal formulärelement som du kan använda men om du lär dig de vanligaste så är det inga problem att sedan implementera ett speciallelement då de i grunden fungerar på samma sätt.

Formulär är front-end

Egentligen tillhör formuläret front-end vilket vi fokuserade på i Webbutveckling01. Jag valde dock avsiktligt att vänta med formulär då vi inte kunde ta emot de inmatade värdena på något sätt. Jag håller på att bygga om kursen Webbutveckling och kommer bygga grunderna kring en tutorial som även har ett bra avsnitt om formulär. Se den gärna, den visar fler möjligheter och inställningar för olika formulärelement än kodgenomgången nedan.

HTML & CSS Full Course for free, 12. forms

3.1.1 Formulärets grundelement

Grunden för ett formulär är <form>-elementet som kan ha flera attribut, de två som behöver finnas är method som talar om enligt vilken metod som innehållet i formuläret skall skickas. action talar om till vilken sida formuläret skall skicka användaren. Denna sidan kommer jag senare referera till som mottagarsidan.

Kodexempel

<form method='post' action='output.php'>
</form>

Rad 1: här skrivs form-taggen med två attribut, method och action. Action anger den sida som vi vill skickas till när formulärets knapp trycks ner. Method är det sättet som information skall skickas på.
Rad 2: här stänger vi formulärtaggen, alla element som finns mellan formulärtaggarna ingår i formuläret.

Webbsidan

Ett formulär utan några formulärelement blir ett helt tomt formulär så det finns inget att rita ut.

3.1.2 input

Input en vanligt element när vi jobbar med formulär, vi skall titta på flera olika sätt som det kan användas.

3.1.2.1 type="text"

I exemplet finns en <input>-tagg med attributet type='text' vilket innebär att det skapas ett element som tar emot en textrad. Det finns ett attribut som heter name='namn' och det är detta namn som sedan skapar en variabel med samma namn som vi kan anropa för att hämta informationen som skickas med formuläret. Mer om detta senare.

Kodexempel

<form method='post' action='output.php'>
  <p>Ange ditt namn<p>
  <input type='text' name='namn'><br>
</form>

Webbsidan

Ange ditt namn


3.1.2.2 type="submit"

Det finns ett input-element med attributet type='submit' och det är den som skapar knappen som skickar formuläret till den sidan dit vi vill skicka formulärets innehåll. Om du klickar på knappen så kommer du till filen output.php i samma mapp som vi redan befinner oss i.

Kodexempel

<form method='post' action='output.php'>
  <input type='submit' value='Skicka' />
</form>

Webbsidan

Alternativ lösning

Ibland kan det finnas anledning att till ett formulär ha två, eller fler, knappar. Då finns det ett element som heter <button> som man kan använda. Notera skillnaden på value vilket gör att man kan läsa av vilken knapp som har använts för att skicka formuläret.

Kodexempel

<form method='post' action='output.php'>
  <button type='submit' name='knapp' value='val_1' />Val 1</button>
  <button type='submit' name='knapp' value='val_2' />Val 2</button>
</form>

Webbsidan

3.1.2.3 type="password"

När vi skriver in lösenord är det bra att detta inte syns i formuläret, det kommer dock att synas i klartext på den sidan dit vi skickar formuläret.

Kodexempel

<form method='post' action='output.php'>
  <p>Ange ditt lösenord:</p>
  <input type='password' name='password' />
</form>

Webbsidan

Ange ditt lösenord:

3.1.2.4 type="radiobutton"

Radioknapp (radiobutton) är bra om vi förväntas göra ett val.

Kodexempel

<form method='post' action='output.php'>
  <p>Ange ditt kön:</p>
  <input type='radio' name='gender' value='female' checked /> Kvinna <br/>
  <input type='radio' name='gender' value='male' /> Man
</form>

Webbsidan

Ange ditt kön:

Kvinna
Man

Här finns några viktiga saker att tänka på

  1. name måste vara samma på alla radioknappar som finns i samma grupp. Här grupperar vi på kön.
  2. attributet checked innebär att det finns ett förvalt alternativ.

3.1.2.5 type="checkbox"

Checkboxen är vanlig när du förväntas godkänna någonting eller som ett element där det bara finns två alternativ, sant/falskt eller ja/nej.

Kodexempel

<form method='post' action='output.php'>
  <input type='checkbox' name='accept' /> Jag godkänner ......
</form>

Webbsidan

Jag godkänner ......

3.1.2.6 type="hidden"

Hidden är bra att använda om vi behöver skicka med gömda värden som vi behöver använda i koden men som användaren inte skall kunna ändra eller behöver se.
OBS: Tänk dock på att det går att se i källkoden så lagra ingen känslig info här såsom lösenord eller liknande.

Kodexempel

<form method='post' action='output.php'>
  <input type='hidden' name='hiddenVar' value='12' />
</form>

Webbsidan

Eftersom elementet inte syns så finns det ingen anledning att visa den som en webbsida, det finns ett exempel på hidden i det stora exemplet nedan.

3.1.3 select

Finns det många val så kan en select-box vara bra att använda, då den innehåller flera alternativ men bara visar den del som är vald.

Kodexempel

<form method='post' action='output.php'>
  <select name='car'>
    <option value='volvo'>Volvo</option>
    <option value='saab'>Saab</option>
    <option value='opel' selected>Opel</option>
    <option value='audi'>Audi</option>
  </select>
</form>

selected innebär att det är förvalt.

Webbsidan

3.1.4 textarea

Att kunna skriva in mer text är ofta intressant, då använder vi istället elementet <textarea>.

Kodexempel

<form method='post' action='output.php'>
  <p>Text:</p>
  <textarea name='content' cols='45' rows='5'></textarea> <br />
</form>

Webbsidan

Text:


3.1.5 Method attribut

Det finns två metoder att skicka information från ett formulär och det är GET och POST.

3.1.5.1 GET

GET används formulärets innehåll vill visas i sidans url. Google använder detta när man gör en sökning. Den stora fördelen med detta är att man kan låta någon annan ta del av samma sökresultat som någon annan fick.
GET används också utan formulär för att skicka information till en sida via url. Det kan tex. vara information om id för ett speciellt inlägg eller en tråd i ett forum.
Exempel: svar.php?firstname=Anna&familyname=Andersson

3.1.5.2 POST

POST skickar informationen dolt för användaren, jämför med att skicka ett kuvert med posten.

3.1.6 Läsa av informationen

Beroende på metod som används för att skicka informationen så lagras innehållet i någon av de superglobala variablerna, $_POST[] eller $_GET[], och dessa fungerar på samma sätt som en array. Indexet i arrayen skapas av det "name" du gav formulärkomponenten. I exemplet ovan så fick textrutan namnet "skickat" vilket ger oss följande kod för att kunna skriva ut innehållet i formuläret;

Kodexempel

<?php
echo($_POST['skickat']);
?>

Hade vi skickat informationen med GET-metoden så hade vi istället fått skriva $_GET['skickat']. Det finns ytterligare en superglobal variabel vi kan använda, $_REQUEST[]. Denna fungerar på samma sätt som $_POST[] och $_GET[] och den innehåller all information som lagras i $_POST[] och $_GET[]. Skickar du information via formulär och url så kan denna vara smidig att använda. Senare kommer vi se att även superglobalen $_COOKIES[] används i $_REQUEST[].

Ibland är det lite svårt att hålla koll på alla index i de superglobala variablerna, speciellt om man använder både $_GET[] och $_POST[] och då kan det vara smidigt att skriva ut innehållet i alla variabler som finns på en sida. Prova gärna bägge för att se skillnaden på resultatet. Det finns tillfälle då du vill använda den ena eller den andra.

En superglobal kan liknas vid färdiga lådor där PHP automatiskt stoppar in värden från formulär eller URL:en.

Kodexempel

<?php
echo "<pre>";
print_r($_POST);
echo "<hr>";
var_dump($_POST);
echo "<hr>";
var_dump(get_defined_vars());
echo "</pre>";
?>

get_defined_vars() skriver ut alla variabler som finns definierade i din kod.

<pre>-taggen är en html-tagg som gör att utskriften av funktionerna ser ut som de skapas, html låter ju annars bli att skriva ut radbrytningar, mellanslag och tabbar.

När du kan bygga enklare formulär så gäller det att kunna ta emot informationen på en mottagarsida och sedan göra någonting med formulärets innehåll.

output.php

<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>Title of the document</title>
   </head>
   <body>
      <h1>Resultat</h1>
      <p>Följande har skickats från formuläret!</p>
      <pre>
        <?php
         // var_dump är en bra funktion som skriver
         // ut allt innehåll i en variabel, i detta
         // fallet en array var_dump($_POST);
         // print_r skriver ut samma sak, fast med
         // lite mindre information. Använd den du vill.
         print_r($_POST);
         ?>
        </pre>
      <a href="javascript:history.back()">Back</a>
   </body>
</html>

output.php är en enkel fil som du kan använda för att själv testa vad som skickas från ditt formulär. Kopiera koden och lägg filen i samma mapp som din formulärsida och se till att du sätter action-attributet till output.php och sedan att du sätter method-attributet till "POST".

Kombinera variabler och strängar vid utskrift

I moment02 så gick vi igenom hur man på några olika sätt kan kombinera strängar och variabler, vilket vi ofta vill göra inom PHP. Här kommer vi märka att PHP har vissa problem med att vara konsekventa, det är inte i alla lägen samma teknik fungerar på olika typer av variabler.

Exempel på utskrifter av variablers innehåll

<?php
// Laddar om sidan med $_GET['mess'] om sådant inte finns
if(!isset($_GET['mess'])){
  header('Location: ?mess=Felmeddelande......');
  exit();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width= , initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Testar olika sätt att skriva ut.</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/mini.css/3.0.1/mini-default.min.css">
  <style>
  .error{ color: red;}
  </style>
</head>
<body>
<h1>Utskrifter av strängar och variabler</h1>
<p>Här visar jag olika sätt att skriva ut strängar som innehåller variabler, som du kan se så är det inte så tydligt vad som funkar, när och hur. <br>
 <a href="?mess=Felmeddelande......">Länken med GET-variabel....</a></p>

<?php
echo "<h2>Använda GET-variabeln direkt....</h2>";
// Använda $_GET-variabeln
echo "<p class='error'>".$_GET['mess']."</p>";
echo "<p class='error'>{$_GET['mess']}</p>";
// echo "<p class='error'>$_GET['mess']</p>"; // Detta sättet fungerar inte....

echo "<h2>Göra om GET-variabeln till \$mess</h2>";
// Använda $mess som variabel
$mess = isset($_GET['mess']) ? $_GET['mess'] : "";
echo "<p class='error'>".$mess."</p>";
echo "<p class='error'>{$mess}</p>";
echo "<p class='error'>${mess}</p>";

echo "<h2>Använda funktionen <a href='https://www.w3schools.com/php/func_string_sprintf.asp' target='_blank'>sprintf()</a></h2>";

// Alternativa sätt att skriva ut
echo sprintf("<p class='error'>%s</p>", $_GET['mess']);
echo sprintf("<p class='error'>%s</p>", $mess);
?>
</body>
</html>

Enklaste sättet att förstå hur det fungerar tror jag är att ta ner koden och testköra den.

3.1.7 Stora exemplet

Dags för ett stort exempel, här samlar jag de element som jag visat ovan samt några till som kan vara bra att känna till eller bara rolia att kunna använda. Du får se både koden och det färdiga formuläret, detta formulär kan du också fylla i och sedan få se vad som kommer till mottagarsidan.

form.html

I denna kod kommer det finnas några saker som behöver förklaras, det gör jag under koden.

[2021-01-20] Här har delar av koden skrivits om då saker som var godkända under HTML 4.1 vad det gäller hanteringen av label klarar inte längre validering för html5.

<form action="output.php" method="POST">
  <p><label for="name">Namn</label>
  <input id="name" type="text" name="name" required placeholder="Ange ditt namn"></p>

  <input type="hidden" name="userId" value="12">

  <p><label for="password">Lösenord</label>
  <input id="password" type="password" name="password" required></p>

  <p><label for="email">Epost</label>
  <input id="email" type="email" name="email" required></p>

  <p><label for="birthday">Födelsedag</label>
  <input id="birthday" type="date" name="birthday"></p>

  <p><label for="color">Favoritfärg</label>
  <input id="color" type="color" name="color"></p>

  <p><label for="happy">Lycklighetskalan</label>
  <input id="happy" type="number" name ="happy" min="1" max="6" step="1" value="1"></p>

  <p><label for="effort">Egen insats</label>
  <input id="effort" type="range" name ="effort" min="1" max="6" step="1" value="1"></p>

  <p><label><input type="checkbox" name="subscribe">Medlemsbrev</label></p>

  <fieldset>
    <legend>Kön</legend>
    <br /><label for="kvinna">Kvinna</label><input id="kvinna" name="gender" value="kvinna" type="radio">
    <br /><label for="man">Man</label><input id="man" name="gender" value="man" type="radio">
  </fieldset>

  <p><label for="contact">Kontakt</label>
  <select id="contact" name="contact" required>
  <option value="">Välj kontakttyp</option>
  <option value="mail">Epost</option>
  <option value="phone">Telefon</option>
  <option value="letter">Brev</option>
  <option value="sms">SMS</option>
  </select></p>

  <textarea name="content" cols="60" rows="6" placeholder="Ange en text"></textarea>

  <p><input type="submit" name="submit" value="send">
  <input type="reset" name="reset" value="reset"></p>
</form>

label - label är en text som kopplas till det formulärelement som har samma namn som labelns for-attribut.

required - gör fältet obligatoriskt.

autofocus - sätts på det element som du vill göra aktivt när du kommer till sidan med formuläret. När du väl har börjat fylla i formuläret så kan du använda tab för att flytta dig till nästa element.

placeholder - definierar en text som finns i ett element där du kan skriva text. Denna text försvinner när användaren skriver någonting.

fieldset/legend - Skapar en ram, och en text, runt ett element och är effektivt när vi vill gruppera någonting.

type = "email" - kontrollerar att texten har format som en e-postadress.

type = "date" - hanterar datum.

type = "number" - ett element som hanterar heltal, du kan antingen skriva eller klicka på pilarna upp och ned, attributen min och max begränsar intervallet på de tal du kan ange, step hanterar vilka steg du kan ta i intervallet och value är det förvalda värdet.

type = "range" - ritar ut en slider men fungerar annars på samma sätt som number.

type = "reset" - denna knappen rensar hela formuläret. Knappen används mer och mer sällan eftesom den inte används så mycket. Det är sällan att du behöver rensa ett helt formulär, antingen ändrar du något värde eller så låter du bli att skicka ett felaktigt formulär.

Webbsidan

Kön

Testa nu formuläret. Du kommer få info om vad du förväntas göra ifall du gör fel. När alla inmatningar stämmer så kommer du skickas till output.php.

3.1.8 Problem med formulär

Det finns några problem med formulärmottagningen som du behöver känna till och kunna ta hänsyn till. Funktionerna var_dump() och print_r() är bra när vi testar formulär men de är ju direkt olämpliga när vi skall skapa färdiga applikationer.

Vi har kikat på hur vi läser av ett formulärelements värde på mottagarsidan och det fungerar utan problem i de flesta fallen. Om vi inte har satt elementet för email till required så kommer arrayen/indexet $_POST['email'] vara tomt. Alla element skapar ett index i arrayen $_POST[] med samma namn som name-attributet, förutom en checkbox eller grupp av radioknapp som ej är ikryssade.

Hur löser vi då det? Radioknapp kan vi komma runt då vi kan sätta ett val från början. Finns det redan ett val så kan vi aldrig bli helt utan val. Checkboxen kräver en annan lösning, här måste vi först kolla om variabeln/arrayen-indexet finns, om den finns så vet vi att den har varit ikryssad, om indexet inte finns så vet vi att rutan inte varit ikryssad. Om vi inte först kollar om indexet finns och anropar det så kommer vi få ett undefined index-error.
På samma sätt kan vi lösa radioknapp om vi inte vill ha ett förvalt alternativ.
Hur du sedan på mottagarsidan vill lösa problemet med att en användare har valt att inte ange kön är en annan fråga.

Koden för kolla om en kryssruta är ikryssad eller inte;

Kodexempel

<?php
if(isset($_POST['subscribe'])){
  echo 'Du vill få medlemsbrev!';
}
?>

isset() är en funktion som kollar om en variabel finns. Innehållet kan vara valfritt värde eller tom sträng, kallas ofta null, men variabeln måste finnas. Detta är intressant när användaren kommer in på en sida där det förväntas följa med ett värde, tex en sida som skall hämta en artikel från ett id via en url. Om detta id inte finns så skapas det fatalt error, sidan kan inte skapas och användaren får ett felmeddelande. Med isset kan det först kontrolleras att en viktig variabel har ett värde och ta hand om det fel som annars skulle uppstått.

isset() är med andra ord användbart för kryssrutor, radioknappar men också för GET-variabler.

Exempel med GET, POST och lite annat [klicka för att visa]

Uppgift: m03u01

Du har fått ett uppdrag att skapa ett anmälningsformulär med följande önskemål;

  • Förnamn och efternamn skall anges i var sin textruta.
  • Födelsedatum skall anges med lämpligt formulärelement.
  • Lösenord skall anges i en ruta med lämpligt formulärelement.
  • Kön skall anges med radioknappar.
  • En kyssruta skall kryssas i att du har godkänt användarvillkoren (inget sådant dokument behöver skrivas).
  • En knapp för att slutföra registreringen skall finnas.
  • Sedan skapar du en mottagarsida som på ett snyggt sätt presenterar formulärets innehåll.
    OBS: var_dump() eller print_r() skall inte användas.

Om du tycker att uppgiften går snabbt att genomföra så lägg lite mer fokus på formulärets utseende. Att bygga snygga webbsidor ingår mer i kursen Webbutveckling01 men eftersom du ändå skall publicera dina uppgifter på webben så gör det ju inget att det ser trevligt ut. Samläser du dessutom kurserna så finns det ju ytterligare anledning att göra detta på ett bra sätt.

Många CSS-ramverk har bra stöd för att göra snygga formulär och oftast är det enkelt att komma igång genom att titta på exempel. Kanske hittar du ett nytt favoritramverk? En enkel sökning på css forms designs eller något liknande ger väldigt många träffar på både guider, kodexempel och ramverk.

Att behärska formulär är en viktig del när vi bygger våra applikationer. Ju mer kontroller vi kan göra front end desto enklare blir det när vi sedan jobbar vidare med vårt data på back end-sidan. Här nedan kommer några exempel på typiska saker som kan vara bra att hantera i ett formulär. Dessa kontroller görs i en kombination av HTML, CSS och JavaScript.

Selectionbox - ej skicka tomt val [klicka för att visa]

Meddelande i inputbox [klicka för att visa]

Kolla identiska lösenord [klicka för att visa]

3.2 Datapersistens

När HTTP (HyperTextTransfer Protocol) används så lagras ingen information om dig som användare. Detta innebär att det som hände på förra sidan inte finns kvar när du kommer till nästa sida. Om vi ändå vill att info skall följa med måste vi själva skapa detta. Detta kan vi göra med;

  • Sessions, en session lagrar information under en kortare tid, den tiden du är aktiv på en sida. När du stänger ner webbläsaren dör sessionen.
  • Cookies, en cookie lagrar information på din hårddisk vilket innebär att det kan finnas kvar information om dig nästa gång du kommer till sidan.

Vi kommer senare i kursen även kika på hur vi lagrar och läser information från filer samt databaser. Alla dessa sätt att lagra data kallas för datapersistens.

3.2.1 Sessioner

Session är en array(/vektor) som fungerar som vilken array som helst med några få undantag. Eftersom den skall leva längre än på en specifik sida måste vi starta sessionen, vilket vi gör genom att starta sessionen längst upp på varje sida där vi vill använda sessionsvariabler. Detta skall skrivas inne i en php-tagg, före all html-kod. Det skall också vara den första kod som du skriver på en sida. Det enda undantag till detta är om det skall koppla objekt till sessionen, då måste deklarationen av objekten göras först. Objektorientering ingår inte i denna kursen.

Kodexempel

<?php
session_start();
?>

3.2.1.1 Hantering av sessioner

Sessionsvariablerna används som vilken array som helst, när vi har satt ett värde på en sessionsvariabel så kan vi anropa denna sessionsvariabel från alla sidor där vi har startat sessionen.

Kodexempel

<?php
session_start();

if($_POST['user'] == "admin" && $_POST['password'] == "qwerty"){
  $_SESSION['userLevel'] = "admin";
}
?>

Glöm inte bort att starta sessionen och att kolla om sessionen finns. Har du varit inaktiv en längre tid så faller sessionen och då försvinner även variablerna. Därför är isset() väldigt bra att använda tillsammans med sessioner. Hur länge en session lever går att ställa in, en bankapplikationen och ett forum har inte samma krav på hur länge du får vara inaktiv, för att ändra hur länge en session skall leva anger du värdet i minuter som argument till funktionen session_cache_expire(15), i detta fall ställer du in så att sessionen skall leva i 15 minuter. Via phpinfo, som du når från din webbserver, kan du se hur din installation ser ut. Hos mig var standardinställningen för MAMP (session.cache_expire) 180 minuter. Min inställning hos Oderland var också 180 minuter. Kolla själv genom att skriva phpinfo(); inom php-taggar och kör den filen.

Ett kortare sidospår. Dags att kolla om användaren är inloggad eller inte.

Kodexempel

<?php
session_start();

if(isset($_SESSION['userLevel']) && $_SESSION['userLevel'] == "admin"){
  echo "Du är admin";
} else {
  echo "Du är inte admin";
}
?>

3.2.1.2 Stänga en session

För att stänga en session och ta bort alla variabler så behöver det göras i följande ordning;

  • Först måste sessionen öppnas som vanligt längst upp på sidan.
  • Sedan måste alla sessionsvariabler tas bort.
  • Slutligen förstörs sessionen.

Kodexempel

<?php
session_start();    // Starta sessionen
session_unset();    // Ta bort alla sessionsvariabler
session_destroy();  // Förstör sessionen
?>

Det kan kännas lite omständigt att först öppna en session för att sedan kunna ta bort och förstöra, men tänk dig att sessionen är som ett skåp, med dörrar, som först måste öppnas innan man kan tömma hyllorna och stänga/förstöra skåpet.

Tömma eller inte tömma sessionen

Det går att ersätta session_unset(); med $_SESSION = Array(); för att tömma sessionen men att inte tömma den på något sätt kommer skapa problem.

Kodexempel

session_start();
$_SESSION['name'] = 'Johan';    // Sätt en variabel
session_destroy();
echo $_SESSION['name'];         // Index + värde finns fortfarande kvar

Utskrift

Johan

Uppgift: m03u02

Skapa ett enkelt formulär där du kan mata in ett namn, lagra sedan detta namnet i en session och skriv ut användarens namn varje gång sidan uppdateras. Skapa sedan en länk där användaren kan döda sessionen och då skall det skrivas ut att det inte finns någon användare!

Tips från coachen: Troligtvis är det enklaste sättet att göra allt i en enda fil och anropa samma sida genom att skriva <a href="?">Ladda om sidan</a>

Exempel på hur sidan kan se ut

Formulärsidan

3.2.2 Cookies

När du surfar på nätet, oavsett om du handlar online, loggar in på en hemsida eller bara sparar inställningar för ett språk, är det mycket möjligt att cookies används i bakgrunden för att förbättra din upplevelse. Men vad är cookies, och hur kan vi som utvecklare använda dem?

Cookies är små textfiler som sparas på användarens dator eller enhet via deras webbläsare. De innehåller ofta information som hjälper webbplatser att komma ihåg viktiga saker, till exempel om en användare är inloggad, vad de har lagt i sin varukorg, eller deras personliga preferenser för hur sidan visas.

Som utvecklare kan vi använda cookies för att göra våra applikationer mer användarvänliga genom att spara information mellan olika besök på en webbplats. Cookies är särskilt användbara när vi vill:

  • Spara användarpreferenser: till exempel tema, språk eller andra personliga inställningar.
  • Hantera sessioner: komma ihåg inloggningar eller spara sessioner för e-handel.
  • Spåra användarbeteenden: analysera hur användare interagerar med en webbplats.

3.2.2.1 Viktigt om regler och lagar

Att använda cookies kräver också att vi följer gällande regler och lagar, särskilt de som rör användarnas integritet. I Sverige regleras cookies av Post- och telestyrelsen (PTS), och enligt lagen måste användare informeras om vilka cookies som används och få en chans att godkänna eller avböja användningen. För att få ett högsta betyg i kursen är det viktigt att ni inte bara förstår hur man tekniskt skapar och hanterar cookies, utan också hur man följer dessa regler.

En bra start är att läsa mer om detta på PTS hemsida: PTS - Kakor (Cookies).

Du som utvecklare måste vara medveten om att det går att stänga av lagringen av cookies, antingen permanent eller temporärt via olika former av inkognito/hemliga lägen. Det viktiga är att vi som utvecklare inte får förlita oss på att cookies alltid fungerar, vi måste även se till att de som stänger av sina cookies får ett trevligt besök på vår webbplats.

Kolla hur många cookies du har via din webbläsare, leta själv reda på hur du hittar cookies i just din webbläsare, det är fler än du tror. Några av dem kan du läsa ut vad de innehåller men de flesta har naturligtvis krypterad information lagrad. När jag kollade på min dator så hade jag 14 cookies från Facebook och 41 cookies från Aftonbladet. Hur påverkar det min vidare surfning om jag tar bort dessa?

3.2.2.2 Tredjepartskaka

Har du någon gång gjort en sökning på en viss produkt för att sedan i Facebook få reklam för just en sådan produkt? Detta kallas för tredjepartskakor och vållar extra stora diskussioner kring användarens integritet. Vad som händer är att ditt sökmönster eller intresse för specifika produkter lagras i cookies som sedan används av någon annan applikation.

3.2.2.3 Skapa och hantera egna cookies

För att skapa en egen cookie i PHP använder vi funktionen setcookie(), som kan ta upp till sex argument:

  • Namn (obligatoriskt): Namnet på cookien, vilket används för att identifiera den.
  • Värde (obligatoriskt): Det värde du vill lagra i cookien, till exempel en användares e-postadress.
  • Utgångsdatum/tid (valfritt): Ett tidsstämpelvärde (i sekunder) som anger när cookien ska upphöra att gälla. Om inget anges förfaller cookien när webbläsaren stängs.
  • Sökväg (valfritt): Definierar vilken del av webbplatsen cookien är tillgänglig för. Som standard är den tillgänglig överallt på din domän.
  • Domän (valfritt): Anger vilken domän som har åtkomst till cookien. Används oftast för att dela cookies mellan flera subdomäner.
  • Säkerhet (valfritt): Används för att kryptera cookien, vilket gör den tillgänglig endast över HTTPS-anslutningar och kan ställas in för att förbättra säkerheten.

Här är ett exempel på hur du kan skapa och läsa en egen cookie:

Kodexempel

<?php
// Definiera en mailadress
$mailadress = "johan@minmail.se";

// Skapa en cookie med namnet 'email' och lagra mailadressen i den
setcookie('email', $mailadress);

// Kontrollera om cookien är satt och skriv ut dess värde
if(isset($_COOKIE['email'])) {
    echo "Din e-postadress är: " . $_COOKIE['email'];
} else {
    echo "Cookien är inte satt ännu.";
}
?>

I exemplet ovan kan ett problem uppstå: det tar vanligtvis lite längre tid för webbläsaren att skapa och lagra en cookie än för servern att generera HTML-koden. Det innebär att cookien kanske inte är tillgänglig om du försöker läsa den direkt efter att du skapat den på samma sida.

En bättre metod är att skapa cookien på en sida och sedan läsa den från en annan sida eller efter en omdirigering. Det är ganska ologiskt att sätta och läsa av en cookie omedelbart på samma plats, eftersom cookien ännu inte hunnit sparas av webbläsaren.

3.2.2.3.1 Testa att hitta cookien

Kör koden ovan och försök sedan hitta cookien som lagras under domänen "localhost" (om du kör din lokala webbserver). Du kan kontrollera detta via webbläsarens utvecklingsverktyg. I Firefox så hittar du det i Inspekteraren och sedan under Lagring->Kakor.

3.2.2.3.2 Ta bort en cookie

För att ta bort en cookie måste du sätta ett utgångsdatum i det förflutna. Här är ett exempel som tar bort den tidigare skapade cookien:

Kodexempel

<?php
// Sätt ett utgångsdatum en timme bakåt för att radera cookien
setcookie('email', '', time() - 3600);
?>

När du kör detta kommando kommer cookien att raderas automatiskt av webbläsaren eftersom den nu anses ha "gått ut".

Uppgift: m03u03

Fortsätt med uppgiften ovan och se nu till att du lagrar namnet som du anger som användarnamn i en cookie. Vad du sedan gör med denna cookie avgör du själv, du kan skriva ut värdet, du kan förifylla formuläret med innehållet i cookien när du har valt att döda sessionen. Träna också på att ta bort din cookie.

Exempel på hur sidan kan se ut

Formulärsidan

3.3 Hantera sessions och cookies i en webbapplikation

I detta avsnitt ska vi gå igenom hur sessions och cookies fungerar, hur de skiljer sig från varandra och när det är lämpligt att använda respektive teknik. Vi kommer också att titta på ett vanligt problem som uppstår när man arbetar med cookies och hur det kan hanteras.

3.3.1 Skillnaden mellan sessions och cookies

Sessions är ett sätt att lagra information på serversidan, vilket innebär att alla data som sparas i en session endast är tillgänglig för servern. Sessionsdata försvinner när användaren stänger webbläsaren eller när sessionen löper ut. Sessioner används ofta för att hantera autentisering (t.ex. inloggningar) eftersom informationen inte delas med klienten (webbläsaren).

Cookies lagras på klientens dator och skickas med varje begäran till servern. De används ofta för att komma ihåg information mellan olika sessioner, till exempel om en användare har markerat en inställning eller är inloggad. Cookies är däremot inte tillgängliga direkt efter att de skapats, vilket kan skapa fördröjning.

3.3.2 När ska du använda sessions eller cookies?

  • Sessions: Används när du behöver lagra känslig information under en användarsession, till exempel inloggningsuppgifter. Eftersom sessions lagras på serversidan är de säkrare än cookies.

  • Cookies: Används för att lagra information över längre tid, t.ex. användarinställningar eller sparad inloggningsinformation. Cookies är synliga för klienten, så du bör undvika att lagra känslig information i dem.

3.3.3 Vanligt problem med cookies

Ett vanligt problem när man arbetar med cookies är att de inte är omedelbart tillgängliga efter att de har skapats. När du skapar en cookie tar det en stund innan den skickas tillbaka till servern, vilket innebär att du inte kan läsa den direkt efter att den satts. Vi kommer att illustrera detta med ett exempel där du behöver ladda om sidan för att se värdet på cookien.

3.3.4 Exempel på att hantera sessioner och cookies

Nedan finns ett exempel som visar hur du kan lagra en e-postadress både i en session och en cookie. Du kan också se hur sessioner och cookies tas bort. Detta skulle kunna vara en alternativ lösning på m03u03.

Kodexempel

<?php
// Starta sessionen
session_start();

// Hantera olika actions via GET-parametrar
if(isset($_GET['action'])){
  switch($_GET['action']){
    case 'killSession':                   // Döda sessionen
      session_unset();
      session_destroy();
      header("location: ?");
      break;
    case 'killCookie':                    // Ta bort cookie
      setcookie('mail',"", time()-3600);
      header("location: ?");
      break;
    case 'reset':                         // Döda sessionen & ta bort cookie
      session_unset();
      session_destroy();
      setcookie('mail',"", time()-3600);
      header("location: ?");
      break;
  }
}

// Om POST-data finns, spara e-post i session och cookie
if(isset($_POST['mail'])){
  $mail = strtolower(trim($_POST['mail']));
  setcookie('mail', $mail);
  $_SESSION['mail'] = $mail;
}
?>
<!DOCTYPE html>
<html lang="sv">
<head>
  <meta charset="UTF-8">
  <title>Exempel på session & cookie</title>
</head>
<body>
  <form action="" method="post">
    <p>Ange en mailadress:<br />
    <input type="email" name="mail" required> <input type="submit"></p>
  </form>
  <hr>
  <?php
  // Kontrollera om sessionen är satt och skriv ut mailadressen
  if(isset($_SESSION['mail'])){
    echo "<p>Mailadressen som är lagrad i session är: ". $_SESSION['mail'];
    echo "<br />[<a href='?action=killSession'>döda sessionen</a>]</p>";
  } else {
    echo "<p>Det finns ingen mail lagrad i SESSION.</p>";
  }

  // Kontrollera om cookien är satt och skriv ut mailadressen
  if(isset($_COOKIE['mail'])){
    echo "<p>Mailadressen som är lagrad i COOKIE är: ".$_COOKIE['mail'];
    echo "<br />[<a href='?action=killCookie'>döda cookien</a>]</p>";
  } else {
    echo "<p>Det finns ingen mail lagrad i COOKIE.</p>";
  }
  ?>
  
  <form action="" method="get">
    <button type="button" onClick="window.location.reload();">reload</button>
    <input type="submit" name="action" value="reset">
  </form>

  <p>När du skriver en mailadress så uppdateras den både i SESSION och COOKIE. Problemet är att cookien inte kan hämtas omedelbart eftersom den måste sparas på klienten först. Klicka på <q>reload</q> för att uppdatera sidan och se värdet på cookien.</p>

  <hr>
  <section style="border:1px dashed black;background:lightgrey;width:800px;">
    <h3>Alla definierade variabler på sidan</h3>
    <div>
      <pre><?php print_r(get_defined_vars()); ?></pre>
    </div>
  </section>
</body>
</html>

3.3.5 Förklaring av koden

Denna applikation lagrar en e-postadress i både en session och en cookie. Den illustrerar följande:

  • Sessioner: E-postadressen lagras i sessionen omedelbart och kan visas direkt.
  • Cookies: E-postadressen lagras i en cookie, men cookien är inte omedelbart tillgänglig. Användaren måste ladda om sidan för att se värdet.

Koden ger också möjlighet att radera sessioner och cookies genom att klicka på länkar. Funktionen för att ta bort en cookie fungerar genom att sätta ett utgångsdatum i det förflutna.

3.3.6 Slutsats

Detta exempel visar både styrkorna och begränsningarna med sessions och cookies. Sessioner är snabbare och säkrare för kortvarig lagring, medan cookies är användbara för långvarig lagring av information, även om de inte är tillgängliga omedelbart efter skapandet. Genom att förstå hur och när dessa tekniker ska användas kan du bygga mer effektiva och användarvänliga webbapplikationer.

Redovisning

Redovisa detta moment på följande sätt;

  1. Lägg upp dina övningar på din hemsida. Lägg dem på en sida med tydliga förklaringar eller skapa flera sidor med olika uppgifter. Viktigt att jag, och andra, kan gå mellan sidorna så vi inte missar något.
  2. Länka sidan/sidorna från din Landing page.
  3. Länka också till CSource och se till att jag den vägen kan se all din kod.
  4. I WordPress så reflekterar du över ditt arbete, berätta vilka uppgifter du gjort och varför. Resonera kring de olika teknikerna och hur du har upplevt dem. Är det rörigt med sessions och cookies eller tycker du att det är någorlunda tydligt hur du skall använda dem och vad du skall använda dem till? Länka också till den sidan, se sidorna, där dina exempeluppgifter finns.
    Frågestöd
    • Hur har arbetet med detta moment gått?
    • Är det någon teknik som är enklare eller svårare att förstå?
    • Vilka resurser har du använt dig av för att lära dig PHP? Någon av de som jag har länkat eller någon annan bra resurs? Har du tips på någon bra resurs så länka gärna denna.