Portál o technologiích a vývoji

Obrázky ve webových aplikacích – Galerie obrázků

Autor: Adam Klvač Datum: 17.10.2013 Počet shlédnutí: 5 422 918x

Obrázkové galerie jsou poslední dobou poměrně populární. Jsou různě veliké a od velikosti se odvíjí způsob nakládání s daty. Je možné se vydat několika způsoby – od ukládání obrázků na server vedle aplikace, přes jednoduchý FTP server až po úložiště velkých hostingů do cloudu. S rostoucí návštěvností se zvyšuje nejenom objem ukládaných dat, ale především přenášených dat. Konektivita našeho serveru může být omezená a pokud začne být zatížení příliš velké, nezbývá nic jiného, než samotné obrázky ukládat jinam. Můžeme využít load balancingu a data distribuovat na servery s lepší konektivitou, které budou pouze jakýmsi skladištěm, v dnešní době je ale poměrně snadno dostupná možnost využití služeb typu Amazon S3.

Každopádně je dobré počítat s tím, že v budoucnu změníme úložiště. Je vhodné k tomu účelu vytvořit jakési rozhraní, které se bude starat o samotné ukládání obrázků a jejich zpřístupnění – typicky tak, že odešleme obrázek na vzdálený server a jeho URL si uložíme (záleží na konkrétní implementaci). V případě nutnosti pak bude stačit změnit rozhraní.

Je vhodné obrázky zmenšovat, o tom jsem již psal v předchozích dílech seriálu. Nyní je vhodné také dodat, že zmenšovat bychom měli na velikosti, které budeme používat pro zobrazení na webu. Platí to pro náhledy i obrázky, které zobrazujeme jako stránku galerie. Pro jistotu doporučuji uchovat i původní velikost nahraného obrázku – co když se rozhodnete zobrazovat náhledy a velké fotky v jiné velikosti? Důvodem pro zmenšení na zobrazovanou velikost je fakt, že budeme přenášet k uživateli jen tak velké obrázky, jak jsou zrovna potřeba (především uživatelé mobilního připojení ví o co jde), navíc prohlížeč nebude muset přepočítávat obrázek pro zobrazení na stránce. Dnes nejde o tak horký problém jako před lety, nicméně taková stránka plná náhledů už nějaký ten čas na vykreslení zabere a správným zmenšením tento čas můžeme zkrátit. Také není na škodu u každého obrázku – alespoň formou CSS – nastavovat velikost. Prohlížeč jinak musí nejdříve stáhnout alespoň hlavičku obrázků, aby byl schopen vypočítat rozložení a my se tak vyhneme nepříjemnému blikání při renderu stránky.

Uživatelé proklikávají galerii po jednotlivých obrázcích a to docela rychle (osobně podobné galerie listuji odhadem obrázek za 5 vteřin), při větším počtu je to dost dotazů, které budeme posílat na databázi a následně zpracovávat. Do databáze zpravidla odesíláme dotaz na zobrazení současného obrázku, ale také alespoň na URL vedlejšího a následujícího. Pokud dodržíme KISS, použijeme 3 dotazy. Možná více – chceme třeba uložit informaci o zobrazení obrázku. Minimálně načtení informací o současném obrázku a „sousedech“ je však možné zredukovat na jeden dotaz pomocí spojení.

SELECT c.*, p.slug AS slug_prev, n.slug AS slug_next
FROM images AS c
LEFT JOIN images AS n ON n.id > c.id
LEFT JOIN (SELECT slug, id FROM images ORDER BY id DESC) p ON p.id < c.id
WHERE c.slug = ? -- Aktuální URI
GROUP BY c.id

Zobrazení obrázků by bylo jistě možné zredukovat také – třeba tím, že si budeme zobrazené obrázky ukládat serializovaně do cookies a pokud jich bude třeba 10, provedeme dotaz, který aktualizuje počty shlédnutí u všech najednou. Některé zpravodajské portály využívají podobný přístup pro ukládání hlasů v anketách – Javascriptem uloží do cookies hlas a zapíší jej při následujícím požadavku.

Použití jednoduchého číslování má několik nevýhod. O jedné jsem již v seriálu psal – usnadní to robotům stáhnout všechny obrázky. Další nevýhodou je fakt, že některé obrázky můžeme smazat a tím se vyskytne v řadě díra, kterou tak jak tak bude nutné řešit.

Problémem, se kterým se mnohé databáze potýkají je linkování obrázků na externí weby. Ať už jde třeba o Google Images, tak o kopírovače obsahu, kteří se ani neobtěžují přetáhnout obrázek k sobě. Obrana existuje – jednou variantou je obrázky zpřístupňovat pomocí vlastní rutiny, která ověří hlavičku referer v HTTP požadavku a pomocí readfile následně provedeme zobrazení, případně uživatele přesměrujeme, či použijeme výmluvné 403 Forbidden.

$referer = parse_url($_SERVER['HTTP_REFERER']);

if(!isset($referer['host']) || $referer['host'] !== 'example.com') {

	// Přesměrování na stránku s obrázkem
	header('Location: http://example.com/obrazek/kotatka');

} else {

	// Detekce MIME
	$finfo = finfo_open(FILEINFO_MIME_TYPE);
	$mime = finfo_file($finfo, $image);
	finfo_close($finfo);

	// Odeslání obrázku
	header('Content-Type: ' . $mime);
	readfile($image);

}

Ve skriptu ukazuji také detekci MIME typu. Pokud by za druhým blokem podmínky následoval ještě nějaký kód, je nutné odchytit jeho výstup a po přesměrování či readfile ideálně provést okamžité ukončení pomocí exit, aby nedošlo omylem k provedení dalšího kódu a aby nebyl obrázek poškozen. Tento způsob nicméně nepovažuji za příliš šťastný. Vykonání tohoto kódu je totiž určitě mnohem náročnější, než snadné zprostředkování skrze webový server, protože se musí načíst PHP interpret a zpracovat kód. Navíc tento způsob nebude fungovat (nebo nebude fungovat příliš rychle) ve chvíli, kdy použijeme externí úložiště. Výhody plynoucí z jeho využití bychom tak naprosto pohřbili, protože přenos by šel přes náš server hned dvakrát (z úložiště a do prohlížeče).

Minimálně v kombinaci s jednoduchým místním úložištěm (či vzdáleném webovém serveru použitém jako skladiště) bych se tedy držel druhé varianty – nechat detekci hlavičky referer na webovém serveru, v tomto případě Apache formou .htaccess konfigurace.

RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://example\.com [NC]
RewriteRule .*\.(jpe?g|gif|bmp|png)$ /images/do-not-link-pictures.jpg [L]

Tento kód podstrčí vlastní obrázek třeba s informačním textem při požadavcích, které mají prázdný referer (například když uživatel vloží odkaz do prohlížeče), nebo ty, na které je odkazováno ze vzdáleného serveru. Pomocí mod_rewrite by bylo také možné zařídit přesměrování na stránku s obrázkem, nebo alespoň hlavní stranu našeho webu.

Pomocí první metody by bylo možné zajistit zobrazení obrázku pouze uživatelům, kteří k tomu mají patřičná oprávnění. V praxi se to nepoužívá a zabezpečují se pouze stránky, kde se obrázek používá, aby nedošlo ke zveřejnění odkazu na obrázek. Důvod, proč dokonce ani Facebook neomezuje přístup přímo k obrázkům je ten, že to nemá smysl. Uživatel sice může zveřejnit odkaz, ale pokud mu v tom zabráníme, zveřejní rovnou celý obrázek. Nebo jej zkrátka ukáže někomu, kdo sedí vedle něj. Technicky méně zdatným uživatelům to sice zabrání v nechtěném šíření obrázku, na druhou stranu méně technicky zdatní uživatelé netropí tak často neplechu a úsilí věnované do zabezpečení se nám zkrátka nevyplatí.

Žádné komentáře

Poslat komentář

Vaše e-mailová adresa nebude zveřejněna.