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.
Ako prvé mi napadlo kódovať binárne dáta pomocou base64, čo by bolo teoreticky bezproblémové, i keď base64‑zakó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 .
O čo teda ide? Schéma umožňuje uložiť ľubovoľné binárne alebo textové dáta priamo v linking‑atribútoch (src
atribút <img>
tagu, či href
atribút <a>
a <area>
tagov). Definovaná je nasledovne:
data:[<mediatype>][;base64],<data>
kde
<mediatype>
je definovaný ako [type “/” subtype] (“;” parameter)*
s defaultnou hodnotou text/plain;charset=US‑ASCII
;base64
značí, že dáta nasledujúce v <data>
položké sú zakódované v base64.Pre uloženie bežného textu Pink elephant priamo do odkazu stačí text zakódovať klasickým URL‑kó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 base64‑kódovaním
<img src="data:image/gif,<data>" /> <img src="data:image/jpeg;base64,<data>" />
ako tu: alebo tu:
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:
Content‑Disposition: attachment
, ktorá prikazuje prehliadaču považovať súbor za externú prílohu2),Content‑Type: application/octet‑stream
, čí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/octet‑stream
.
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 Content‑Disposition
, 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.
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 Content‑Disposition: 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 Content‑Disposition
):
<a href="data:image/jpeg;base64,..." download="PredvolenýNázovObrázku.jpg">obrázok</a>
viď obrázok.