T&R splet blog o spletnih storitvah. Razgaljamo tehnologijo!

reference spletnih strani
16th October

Manipulacija slik s PHP-jem – cache slik – 304 Not Modified

Pri večjih projektov se pogosto srečujemo s problemi kako eno sliko uporabiti v različnih velikostih in mestih na naši spletni strani. Podoben primer je tudi, ko uporabnik doda nekaj fotografij, ki pa niso iste velikosti. V primeru, da pustimo uporabniku celoten nadzor nad velikostjo posameznih slik nam lahko pokvari design zaradi prevelike ali premajhne slike, v primeru pa da velikost določimo z img height ter width atributom pa lahko pride do popačenosti same slike.

Zato si poglejmo preprosto PHP skripto, ki bo podano sliko spremenila na nam žaljeno velikost. Dodatna prednost te PHP skripte je tudi možnost centralnega shranjevanje (cache) vseh slik. Željeno velikost slike bomo podali preko parametrov.

Koda PHP skripte

[php]
// Dobimo vse parametre
$image = (isset($_GET['src']) ? $_GET['src'] : ‘random.jpg’);
$width = (isset($_GET['w']) ? $_GET['w'] : 150);
$height = (isset($_GET['h']) ? $_GET['h'] : 140);

if (!file_exists(“images/$image”)) {
$image = ‘images/random.jpg';
}

// Standardiziramo ime datoteke
$imageBasename = basename($image);
$extension = pathinfo($imageBasename, PATHINFO_EXTENSION);
$imageBasename = str_replace(‘.’.$extension, ”, $imageBasename); // odstranimo končnico

// Dodamo width, height atribut tako da imamo lahko cache iste slike v različnih dimenzijah
$imageBasename = $imageBasename . ‘_’ . $width . ‘_’ . $height;
$imageBasename .= ‘.’.strtolower(‘png’); // vse slike bomo izpisovali kot png

// V primeru da cache ni prisoten kreiramo novo sliko
if (!file_exists(“cacheImages/$imageBasename”)) {
require_once ‘wideimage/WideImage.inc.php';

$img = wiImage::load(“images/$image”);
$res = $img->resize($width, $height, ‘inside’);
$res->saveToFile(“cacheImages/$imageBasename”);
}

// Pregledamo ali ima client sliko v browser cachu preko last modified time
$lastModifiedTime = filemtime(“cacheImages/$imageBasename”);
$etag = md5_file(“cacheImages/$imageBasename”);

header(“Last-Modified: “.gmdate(“D, d M Y H:i:s”, $lastModifiedTime).” GMT”);
header(“Etag: $etag”);

if ( isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])
&& strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModifiedTime ||
( isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag)
) {
header(“HTTP/1.1 304 Not Modified”);
exit;
}

// V primeru, da slike browser nima v cachu jo prikažemo
header(‘Content-type: image/png’);
readfile(“cacheImages/$imageBasename”);
exit;
[/php]

Kratek opis skripte za manipulacijo slik:

Najprej pridobimo vse potrebne informacije. Preverimo ali slika obstaja in v primeru, da ne obstaja prikažemo neko random sliko preko katere takoj vemo, da je s sliko nekaj narobe. Lahko vrnemo tudi 404 not found. Nato kreiramo unikatno ime slike in sicer tako, da dodamo še width ter height atributa. S tem dosežemo, da lahko za posamezno sliko kreiramo več začasnih datotek oz. cache datotek za različne velikosti. V primeru, da slike ni moč najti v začasnih datotek jo s pomočjo wideimage knjižnice zmanjšamo oz. povečamo ter shranimo. Vse, kar nam ostane je še preverjanje ali ima obiskovalec sliko v browser cachu preko HTTP_IF_MODIFIED_SINCE http headerja. V primeru, da slike v cachu nima jo normalno izpišemo.

Za delo s slikami smo uporabili meni zelo všečno wideImage knjižnico o kateri smo na T&R splet že pisali.

Rezultati – izboljšanje hitrosti

Za preverjanje rezultatov uporabite Firefox ter Firebug dodatek, kjer boste lahko videli ali vam PHP skripta pravilno začasno shranjuje datoteke (cache) ali ne. Ko imate enkrat sliko naloženo jo bo naslednjič brskalnik naložil iz internega cache sistema. Če pritisnite F5 bo brskalnik preveril ali potrebuje novo sliko ali lahko uporabo tisto iz cache sistema. V primeru, da vrnemo 304 Not Modified jo bo brskanil vzel iz cache, v nasprotnem primeru pa je bo ponovno prenesel iz strežnika. Preverjanju pa se lahko izgonemo z ctrl + f5, kjer bo brskalnik v vsakem primeru iz strežnika ponovno naložil sliko.

Dodatne informacije:


4x komentirano na “Manipulacija slik s PHP-jem – cache slik – 304 Not Modified”

  1. gasper_k je napisal:

    Ker lahko za e-tag pošlješ praktično karkoli, je malenkost bolj prijazno do strežnika, če uporabiš npr. md5($lastModifiedTime . $imageBaseName). Na ta način php ne gre odpirati in brati datoteke, e-tag pa je enako unikaten in se spremeni šele, ko se spremeni $lastModifiedTime. Resda je lahko vsebina ista (če datoteko ponovno skopiraš na strežnik), ampak lahko pa je dovolj dobro.

    Druga stvar je Expires header, ki ga močno priporočam. Ta brskalniku pove, kdaj bo datoteka zagotovo zastarana, do takrat pa je brskalnik sploh ne zahteva več s strežnika. Če delaš keširanje nespremeljivih datotek, lahko mirno postaviš Expires daleč v prihodnost in si prišparaš ne samo prenos cele datoteke, ampak kar en request manj.

  2. Roky je napisal:

    Expires header, se strinjam, edino ne vem koliko daleč v prihodnost bi nastavil, max 10 dni …?

  3. gasper_k je napisal:

    Če se resource res redko spreminja, potem mirno daš tudi več (2, 3 tedne). Problem se pojavi, če spremeniš sliko in večina obiskovalcev tega ne opazi par dni, ker brskalnik nove slike ne zahteva. To rešiš potem tako, da jo daš na strežnik pod drugim imenom. Enostaven pristop je ta, da statične datoteke posnameš na strežnik in jim pripneš št. svn revizije zraven imena (header-logo-r2135.png), Expires pa postaviš kar se da daleč. Na ta način efektivno keširaš, hkrati pa lahko praktično v trenutku cache razveljaviš.

  4. Roky je napisal:

    gasper_k, zanimivo. Moram enkrat še probat to zadevo čez celotne statične datoteke (css, js) in dodati še gzip, pa zadevo malce pretestirati, da vidim kako se obnese. Tnx za info.

Dodaj komentar

You must be logged in to post a comment.