Uvod
Nedugo posle početnog upoznavanja sa web dizajnom i bekend programiranjem, programeri se prirodno susretnu sa potrebom za lokalnim skladištenjem podataka koje browseri koriste. Od browsera očekujemo da "pamte" da smo prijavljeni na određeni sajt (da ne bismo morali ponovo da unosimo podatke za prijavu), prethodni sadržaj korpe pri online kupovini, boju pozadine i veličinu fonta koju smo izabrali i slično.
Ovakve stvari se svakako podrazumevaju (godinama unazad), ali - ne dešavaju se ipak "same od sebe".
Da bi sajtovi koje kreiramo imali opcije koje smo prethodno naveli (kao i druge, srodne opcije), moramo koristiti lokalna skladišta podataka.
Razlike između web kukija i lokalnog skladištenja
Verujemo da je našim čitaocima dobro poznat pojam HTTP kolačića ili kukija (engl. - cookie), kao metode za lokalno skladištenje podataka koje browser koristi. Kukiji jesu opšteprisutni i veoma korisni, ali, zahtevaju pažnju po pitanju pravilne implemetacije i (napomenimo takođe) nisu jedini način za lokalno skladištenje podataka.
Sam po sebi, kuki predstavlja nisku (string, tekstualni podatak) koja se kreira na serveru, šalje browseru i skladišti lokalno. U daljoj obradi podataka, kukiji postaju deo HTTP zahteva koji se šalju sajtu (prosto rečeno, svaki put kada se sajt obraća serveru, šalju se i kukiji koje je sajt prethodno od servera primio), tako da moramo voditi računa o njihovoj veličini (mada, budući da je maksimalna veličina jednog kukija 4KB, praktičnije je reći da moramo voditi računa o ukupnom broju kukija koje naš sajt koristi, jer veličina jednog kukija nije nešto što u današnje vreme predstavlja iole ozbiljniji problem).
Kukijima možemo pristupati preko serverskih jezika (kao što je PHP), dok, kada je u pitanju podrška za JavaScript, stvari funkcionišu malo drugačije: možemo kreirati kukije koji se mogu čitati samo na serveru (iz sigurnosnih razloga), kao i one kojima se može pristupati preko JavaScripta-a.
Međutim (kao što smo već spomenuli), ne moramo koristiti "uvek i samo" kukije za lokalno skladištenje podataka (pogotovo s obzirom na to što smo već naveli da se kukiji šalju serveru sa svakim HTTP zahtevom), već, pogotovo za "običnije" zahteve, možemo koristiti i lokalna skladišta koja su dostupna browserima.
U nastavku, upoznaćemo se sa načinima za pristup navedenim resursima (kukijima i lokalnim skladištima).
Operacije sa lokalnim skladištem preko JavaScript-a
Za sam početak, upoznaćemo se sa operacijama vezanim za skladištenje podataka browsera koje se obavlja "u lokalu" (preko frontend jezika).
JavaScript za ovu namenu koristi objekate sessionStorage
i localStorage
i, iako pomenuta dva objekta imaju mnogo sličnosti i gotovo identičnu sintaksu za pozivanje komandi, postoje razlike (i ralozi zašto ćemo u različitim okolnostima koristiti jednu ili drugu opciju):
- sessionStorage - podaci su vezani za sesiju i brišu se pri zatvaranju browsera
- localStorage - podaci ostaju trajno zapisani (odnosno, dok se ne obrišu ručno)
Objekat sessionStorage
možemo koristiti za (recimo) pamćenje sadržaja tekstualnih pojla, u situacijama kada ne želimo da se posle osvežavanja stranice sadržaj izgubi, dok localStorage
možemo koristiti za pamćenje večičina fonta, boja elemenata koje je korisnik izabrao (i tome slično).
Skladištenje podataka
Skladištenje podataka obavićemo pozivom komande setItem()
, kojoj ćemo kao argmente predati ključ (identifikator preko koga ćemo nadalje obraćati podatku) i vrednost.
// Za upis u skladište koje je vezano za sesiju:
sessionStorage.setItem("boja_pozadine", "#2244ee");
// Za upis u lokalno skladište browsera:
localStorage.setItem("boja_pozadine", "#2244ee");
Čitanje podataka
Za čitanje podatka koji smo već upisali, možemo koristiti funkciju getItem()
, kojoj ćemo kao argument predati ključ nekog od podataka:
// Za čitanje podataka iz skladišta koje je vezano za sesiju:
var bojaPozadine = sessionStorage.getItem("boja_pozadine");
// Za čitanje podataka iz lokalnog skladišta browsera:
var bojPozadine = localStorage.getItem("boja_pozadine");
// U oba slučaja, promenljiva bojaPozadine
// dobija vrednost "#2244ee"
Uklanjanje podataka
Za uklanjanje podataka, koristićemo funkciju removeItem()
(uz predavanje ključa), ukoliko želimo da uklonimo određeni podatak, ili, clearAll()
, ukoliko želimo da ukonimo sve podatke iz lokalnog skladišta.
// Za uklanjanje podataka iz skladišta koje je vezano za sesiju:
sessionStorage.removeItem("boja_pozadine");
// Za čitanje podataka iz lokalnog skladišta browsera:
localStorage.removeItem("boja_pozadine");
// U oba slučaja, podatak sa ključem
// bojaPozadine biće uklonjen.
// Ukoliko želimo da ispraznimo skladišta
// podataka u potpunosti, koristićemo sledeći kod:
sessionStorage.clearAll();
// ... ili ....
localStorage.clearAll();
Rad sa kukijima je nešto složeniji. Podaci smešteni u sessionStorage
ističu po zatvaranju browsera, dok oni smešteni u localStorage
ne ističu (dok se sami za to ne "pobrinemo") nikad. Kada su u pitanju kukiji, pored ključeva i vrednosti, možemo (ili, u određenim okolnostima, pogotovo kada nas na to navode sigurnosni razlozi - moramo), navesti i trenutak isteka, kao i to da li je u pitanju kuki koji se može čitati samo na serveru (a takođe i domen i putanju za koje kuki važi).
U nastavku, pozabavićemo se obradom kukija u PHP-u i JavaScript-u.
Operacije sa kukijima u PHP-u
PHP, kao serverski jezik, nudi dobru podršku za kukije i raspolaže svim neophodnim funkcijama za raspolaganje ovim resursima.
Krenimo redom ...
Kreiranje i ažuriranje kukija
Za kreiranje kukija preko PHP-a, koristićemo sledeći kod:
<?php
setcookie(naziv, vrednost, trenutak_isteka, domen);
?>
Da bismo bolje razumeli šta navedeni argumenti označavaju, pogledaćemo primer:
<?php
$boja_pozadine = "#44ee11";
setcookie("boja_pozadine", $boja_pozadine, time() + 86400 * 30, "/");
// Ako želimo, možemo to uraditi i ovako:
//
// $boja_pozadine = "#44ee11";
// $naziv_kukija = "boja_pozadine";
// setcookie($naziv_kukija, $boja_pozadine, time() + 86400 * 30, "/");
//
// ARGUMENTI SU:
//
// naziv: "boja_pozadine" - naziv po kome ćemo (nadalje)
// prepoznavati dati kuki
// vrednost: $boja_pozadine - vrednost koju upisujemo u kuki
// (najvažniji argument) biće vrednost promenljive
// $boja_pozadine ("#44ee11")
// trenutak_isteka: time() + 86400 * 30 - označava trenutak u kome
// kuki ističe i zadaje se u sekundama;
// Preko funkcije time(), dobijamo broj sekundi po
// UNIX Timestamp koji odgovara trenutnom vremenu,
// dok je 86400 broj sekundi u jednom danu:
// 86400 = 24 * 60 * 60
// .... što znači da naš kuki ističe za 30 dana
// od trenutka kada pozivamo funkciju setcookie()
// domen: "/" - Ovim deklarišemo kuki koji će važiti za
// ceo domen
?>
Za ažuriranje (u našem slučaju, ako korisnik promeni boju pozadine), jednostavno ćemo ponovo pozvati funkciju setcookie()
i predati drugi vrednost:
<?php
$boja_pozadine = "#332aff";
setcookie("boja_pozadine", $boja_pozadine, time() + 86400 * 30, "/");
// Sve je "isto", ali, ovoga puta predajemo vrednost:
// "#332aff"
?>
Sada je kuki dostupan širom domena (svim stranicama sajta) i možemmo mu lako pristupiti.
Pristup kukijima
Za pristup kukijima, koristićemo superglobalnu promenljivu $_COOKIE
, sa odgovarajućim indeksima koji (kao što verovatno pretpostavljate) odgovaraju nazivima kukija koje smo zadavali kada smo pozivali funkciju setcookie()
.
Naravno, da bi sve imalo pravog smisla, pre nego što pristupimo kukiju, prvo ćemo proveriti da li dati kuki postoji, za šta ćemo koristiti do sada dobro poznatu funkciju isset()
:
<?php
// Podrazumevana boja pozadine je bela:
$boja_pozadine = "#fff";
$poruka = "";
if(isset($_COOKIE['boja_pozadine']))
{
$boja_pozadine = $_COOKIE['boja_pozadine'];
}
echo "<font color='" . $boja_pozadine . "'>Ispis</font>";
?>
Uklanjanje kukija
Kukiji se uklanjaju na jednostavan, ali pomalo idiosinkratičan, način - pozivanjem funkcije setcookie()
, pri čemu se za trenutak_isteka zadaje trenutak u prošlosti:
<?php
setcookie("boja_pozadine", "", 1, "/");
// naziv: "boja_pozadine" - Preko prvog argumenta,
// određujemo koji je kuki predviđen za brisanje
// vrednost: "" - Prilično je svejedno, ali, pri brisanju
// kukija tipično se zadaje vrednost koja dodatno
// sugeriše da je u pitanju uklanjanje
// trenutak_isteka : 1 - UNIX Timestamp za 20.03.2021 u 10h
// (vreme je ovaj članak kreiran), funkcija time()
// vraća vrednost 1616230800, što veoma jasno
// pokazuje da vrednost 1 označava
// "trenutak u prošlosti"
?>
Za kraj, ostaje nam nešto što ćemo u praksi raditi na samom početku - da proverimo da li browser uopšte dozvoljava kreiranje kukija (ako se pitate zašto je ovo uopšte neophodno, podsetićemo vas da internet browseri omogućavaju automatsko brisanje kukija pri zatvaranju) ....
Provera da li browser podržava kukije
Iako PHP nema specijalizovanu funkciju za kreiranje kukija, proveru možemo jednostavno obaviti na sledeći način:
- kreiraćemo kuki određenog naziva
- proverićemo da li dati kuki postoji
<?php
setcookie("proba", "proba kukija", time() + 3600, "/");
if(isset($_COOKIE['proba']))
{
echo "Čuvanje kukija je omogućeno.";
// U praksi, u slučaju da je čuvanje kukija omogućeno,
// nećemo (nepotrebno) o tome obaveštavati korisnika
}
else
{
echo "Čuvanje kukija nije dozvoljeno!";
// U praksi, u slučaju da je čuvanje kukija nije omogućeno,
// moramo ipak naći elegantniji način da o tome
// obavestimo korisnika
}
?>
Takođe, u prethodnoj skripti, možemo koristiti i drugačiji uslov ....
<?php
// ....
if(count($_COOKIE) > 0)
// ....
?>
.... što navodimo (iako je prethodni kod zanimljiv sam po sebi), pre svega iz razloga što verujemo da će naši čitaoci naći bolje i kreativnije načine da iskoriste mogućnost prebrojavanja postojećih kukija.
Pošto smo se, kroz primere u PHP-u, upoznali sa opštim principima čuvanja i obrade kukija, pogledaćemo kako sve navedene operacije možemo koristiti u JavaScript-u.
Operacije sa kukijima u JavaScript-u
JavaScript kao skriptni jezik takođe nudi dobru podršku za rad sa kukijima, ali, mora se priznati da se oko nekih stvari ipak moramo malo više potruditi nego što je to slučaj sa PHP-om.
Najbolje je da to ipak shvatimo kao priliku da se dodatno upoznamo sa ovim jezikom i utvrdimo ono što smo do sada naučili (pogotovo kada je u pitanju rad sa nizovima).
Kreiranje kukija
Za kreiranje kukija preko JavaScript-a, pozivaćemo kod po sledećem obrascu:
document.cookie = "naziv=vrednost; expires=datum; path=/";
Iako je kod naizgled drugačiji, prepoznajemo princip sa kojim smo se upoznali u odeljku o kukijima u PHP-u: predajemo naziv kukija, vrednost, vreme isteka i domen.
Deluje jednostavno, međutim, kada je u pitanju unos datuma, potrebno je koristiti sledeći format zapisa ....
Thu, 01 Jan 1970 00:00:00 UTC
.... što ni iz daleka nije intuitivno.
Da bismo olakšali sebi posao dodavanja novog kukija, kreiraćemo pomoćnu funkciju koja će kreirati nisku za dodavanje kukija - onako kako to od nas zahteva jezik JavaScript:
function formatiranjeKukija(naziv, vrednost, dani, sati, domen) {
let datum = new Date();
datum.setTime(datum.getTime() + (dani * 86400 + sati * 3600) * 1000);
return naziv + "=" + "vrednost; " +
"expires=" + datum.toUTCString() +
((domen != "")? "; path=" + domen : "");
//*/
}
Princip je skoro isti kao u prethodnom slučaju (kada smo koristili PHP):
- objekat klase
Date
(datum) beleži datum - metoda
getTime()
upisuje trenutni datum u objekat datum -
na vreme koje zada prethodna metoda dodaćemo:
- dani * 86400 (broj dana * broj sekundi u jednom danu)
- sati * 3600 (broj sati * broj sekundi u jednom satu)
- zbir prethodne dve vrednosti pomnožićemo sa 1000, budući da metoda
setTime()
operiše sa milisekundama - preko metode
toUTCString()
kreiraćemo format koji je neophodno koristiti pri kreiranju kukija u JS-u
Ako sada pozovemo sledeći kod:
document.cookie = formatiranjeKukija("boja_pozadine", "#2244ee", 30, 0, "/");
.... lako ćemo postaviti novi kuki.
Pristup kukijima
Ovo je (moramo priznati) najmanje jednostavan deo, kada su u pitanju kukiji u JavaSkript-u.
Za pristup kukijima, JS nam nudi samo da preuzmemo sve kukije, u obliku niske, preko sledećeg koda:
var kukiji = document.cookie;
.... pri čemu ćemo samo dobiti nisku sledećeg formata:
"korisnik=darth_vader"; id=411; boja_pozadine=#2244ee"
Međutim, budući da su delovi niske razdvojeni znakom tačka-zarez, lako ćemo datu nisku, preko komande split()
, pretvoriti u niz čijim elementima možemo pristupati pojedinačno:
kukiji = kukiji.split(";");
.... pri čemu promenljiva kukiji više nije obična niska, već (višedimenzionalni) niz sledećeg sadržaja:
[
"korisnik=darth_vader",
" id=411",
" boja_pozadine=#2244ee"
]
U pitanju je niz niski, u kome svaka pojedinačna niska sadrži dva podatka (naziv i vrednost), razdvojena znakom jednakosti.
Pri svakom obraćanju ovim pojedinačnim niskama možemo, ponovo preko komande split()
, kreirati pomoćnu promenljivu red
- niz koji sadrži naziv kukija i pripadajuću vrednost:
let red = kukiji[0].split("=");
// red = ["korisnik", "darth_vader"];
red = kukiji[1].split("=");
// red = [" id", "411"];
red = kukiji[2].split("=");
// red = [" boja_pozadine", "#2244ee"];
Primećujemo da, u drugom i trećem nizu, prva niska sadrži razmak na početku, što je neizbežno, ali lako rešivo (u daljoj obradi) preko komande trim().
Pošto su nam poznati svi detalji, možemo napraviti jednostavnu funkciju koja će pronaći sadržaj određenog kukija (ili ustanoviti da traženi kuki ne postoji):
function pronalazenjeKukija(naziv) {
let kukiji = document.cookie;
kukiji = kukiji.split(";");
// kukiji = [
// "naziv_1=vrednost_1",
// " naziv_2=vrednost_2",
// " naziv_3=vrednost_3",
// ....
// " naziv_n=vrednost_n",
// ];
for (let i = 0; i < kukiji.length; i++) {
// kukiji[i] = "naziv_i=vrednost_i";
let red = kukiji[i].trim().split("=");
// red = ["naziv_i", "vrednost_i"];
if(red[0] == naziv) {
return red[1];
}
}
return false;
}
Vama ostavljamo da gornju funkciju (koja je krajnje adekvatna za svakodnevnu upotrebu), dodatno optimizujete.
Uklanjanje kukija
Za uklanjanje kukija koristimo poznati princip: pozivamo metodu za dodavanje/ažuriranje kukija u kojoj kao poništavamo vrednost i takođe, kao vreme isteka, navodimo "trenutak u prošlosti".
Ovoga puta, kao "trenutak u prošlosti", sasvim dobro će poslužiti početak UTC epohe - 01.01.1970.
Ako pozovemo sledeći kod:
document.cookie = "boja_pozadine=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
.... kuki će biti uklonjen.
Provera da li browser podržava kukije
Kao što smo naveli u odeljku o kukijima u PHP-u, provera podržanosti kukija preko JavaScript-a je krajnje jednostavna:
if(navigator.cookieEnabled)
{
alert("Čuvanje kukija je omogućeno.");
// U praksi, u slučaju da je čuvanje kukija omogućeno,
// nećemo (nepotrebno) o tome obaveštavati korisnika
}
else
{
alert("Čuvanje kukija nije dozvoljeno!");
// U praksi, u slučaju da je čuvanje kukija nije omogućeno,
// naći ćemo elegantniji način da o tome obavestimo korisnika
}
Naravno, i ovde ćemo poštovati primedbe koje smo naveli u komentarima (o tome da su kukiji podržani nećemo nepotrebno obaveštavati korisnike, a, u slučaju da kukiji nisu podržani, pronaći ćemo elegantniji način da korisnike obavestimo o tome).
Zaključak
Na kraju, pošto smo se upoznali sa mehanizmima za "trajno" čuvajne podataka iz browsera na računaru klijenta, možemo preći na sledeći (reklo bi se "prirodan") korak.
U pitanju je autentifikacija (čime smo se već, u velikoj meri, pozabavili u tutorijalu za kreiranje forme za prijavu) i autorizacija korisnika, što će biti tema narednog članka ....