Obsah

Ukladanie binárnych súborov do HTML kódu

Už dlhšiu dobu riešim otázku, akým spôsobom skladovať binárne súbory (obrázky, resources apod.) patriace k Dokee dokumentu tak, aby nemuseli byť na disku uložené samostatne, ale priamo v dokumente.

Prvé myšlienky

Ako prvé mi napadlo kódovať binárne dáta pomocou base64, čo by bolo teoreticky bezproblémové, i keď base64zakódované dáta zaberajú 4×viac miesta. Problém ale nastáva pri ich zobrazení — nebol som schopný prísť na nejaký rozumný spôsob, ako takéto dáta JavaScriptom predať do src atribútu <img> tagov.

Našťastie mi dnes Juraj poslal sprievodcu Brnom vo formáte *.html :). Súbor mal veľkosť 13MB, čo bolo na prvý pohľad podozrivé: je to len *.mht súbor so zlou príponou, alebo vírus? Tak som si rovno pozrel zdroják… <img> tagy mali v src atribútoch nejaký binárny bordel začínajúci vždy prefixom

data:image/jpeg;base64,

a po chvíľke googlenia som zistil, že som našiel presne to, čo potrebujem — a síce data: schému, definovanú už v roku 19981), čo je výborné, lebo za ten čas ju plne podporuje dokonca aj Explorer :D.

Data: URL schéma

O čo teda ide? Schéma umožňuje uložiť ľubovoľné binárne alebo textové dáta priamo v linkingatribútoch (src atribút <img> tagu, či href atribút <a> a <area> tagov). Definovaná je nasledovne:

data:[<mediatype>][;base64],<data>

kde

Pre uloženie bežného textu Pink elephant priamo do odkazu stačí text zakódovať klasickým URLkódovaním

<a href="data:,Pink%20elephant">text</a>

viď odkaz. Pre vloženie obrázku môžeme jeho binárne dáta zakódovať URL alebo base64kódovaním

<img src="data:image/gif,<data>" />
<img src="data:image/jpeg;base64,<data>" />

ako tu: obrázok alebo tu: fotka

Sťahovanie vložených dát

S použitím vložených dát sa vynára dôležitá otázka: ako zabezpečiť, aby po kliknutí na odkaz prehliadač nezobrazil vložený obsah, ale ponúkol jeho stiahnutie? Pri binárnych súboroch generovaných pomocou PHP sa využívajú dva postupy:

  1. použitím hlavičky ContentDisposition: attachment, ktorá prikazuje prehliadaču považovať súbor za externú prílohu2),
  2. alebo hlavičkou ContentType: application/octetstream, čím prehliadaču dávame najavo, že ide o tok binárnych dát neznámeho typu, takže by sa nemal snažiť ich otvárať.

Prvý spôsob sa používa častejšie, je lepšie podporovaný a v podstate jediný správny, keďže druhý nie je sémanticky čistý — napokon, sťahovaný súbor môže byť aj čistý plaintext, čo určite nie je neznámy druh binárnych dát, ako tvrdíme hodnotou application/octetstream.

Do príchodu HTML5 bolo možné pre sťahovanie vložených dát používať len druhý spôsob. Ak by sme predchádzajúci obrázok chceli ponúknuť na stiahnutie, zmenili by sme typ dát a kód by vyzeral nasledovne:

<a href="data:application/octet-stream;base64,...">obrázok</a>

viď obrázok. Problém s týmto prístupom je v prvom rade v tom, že — ako sme si už povedali — nie je správny. Druhý problém je technický: nemáme možnosť oznámiť prehliadaču, aký predvolený názov by mal ponúknuť pre súbor. V PHP bol problém vyriešený už spomínanou hlavičkou ContentDisposition, ktorá obsahovala nepovinný atribút filename, takže nastaviť predvolený názov súboru bolo jednoduché:

header("Content-Disposition: attachment; filename="myFile.jpg");

Pre podobnú funkcionalitu v HTML sme si museli počkať na príchod verzie 5.

Novinky v HTML5

HTML5 pridáva tagom <a> a <area> nový atribút download, ktorého prítomnosť vraví prehliadaču, že má k obsahu, na ktorý odkaz smeruje, pristupovať ako k externej prílohe. To je ekvivalentné použitiu hlavičky ContentDisposition: attachment v PHP a zaručuje, že súbor nebude otvorený, ale ponúknutý užívateľovi na stiahnutie3).

Naviac v prípade, že atribútu download nastavíme nejakú hodnotu, bude táto prehliadačom považovaná za predvolený názov súboru (rovnako ako v PHP použitím atribútu filename s hlavičkou ContentDisposition):

<a href="data:image/jpeg;base64,..." download="PredvolenýNázovObrázku.jpg">obrázok</a>

viď obrázok.

Externé odkazy

Komentáre

2)
definované v RFC6266
3)
viď špecifikáciu HTML5 na W3C, prípadne zrozumiteľnejšie na WHATWG