Upload binárního souboru z JS do PHP

HTTP protokol není vhodný pro přenos binárních dat a prohlížeče to většinou řeší nejrůznějším šifrováním. Pokud ale chcete sami z JavaScriptu nahrát nějaký soubor na server a nechcete se příliš zabývat složitostmi, můžete použít trik se zakódováním do Base64.

Odeslání z JS

Nejprve je potřeba v JavaScriptu načíst soubor a převést ho na Base64:

f = new FileReader();
f.onload = function(e) {
    $.ajax({
        url: 'upload.php',
        type: 'POST',
        contentType: 
   'application/octet-stream;charset=UTF-8',
        data: e.target.result
                .split(",", 2)[1],
        processData: false
    });
};
f.readAsDataURL($('input')[0].files[0]);

Je potřeba si dát pozor na několik věcí:

  1. FileReader nemusí být podporován ve starších prohlížečích.
  2. ContentType musí uvádět UTF-8, aby nedošlo k nechtěnému překódování dat (i když Base64 by měl být bezpečný).
  3. Funkce readAsDataUrl vrací textovou hlavičku pro použití v HTML atributu src. Pro odeslání na server ji musíme odebrat (smazat vše před čárkou).
  4. jQuery $('input') je potřeba nahradit za správný kód pro získání inputu typu file.
  5. FileReader je asynchronní, proto musíme nejprve uložit handler pro onload a pak teprve zavolat funkci pro načtení souboru.

Uložení na serveru

Následně v PHP (nebo jakémkoliv jiném jazyce) stačí přečíst POST data, dekódovat je z Base64 a uložit:

$base64 = file_get_contents('php://input');
$data = base64_decode($base64);
file_put_contents(STORE . $filename, $data);

Práce s daty v PHP je jednoduchá, i když trochu zrádná pro nezkušeného programátora:

  1. Data ze vstupu čteme z php://input, který obsahuje data tak, jak vypadala před dekódováním do $_POST. Proměnná $_POST se totiž dá použít jen na správně formátovaná data a je nevhodná pro binární data, JSON, XML (SOAP), apod.
  2. Funkce file_*_contents() usnadňují práci se soubory a odstraňují nutnost je otevírat a zase zavírat.
  3. Načtená data jsou v Base64, takže je musíme před uložením na disk zase dekódovat.
  4. Konstanta STORE a proměnná $filename by měly obsahovat cestu a jméno pro uložení souboru.

Na závěr jedna připomínka: Base64 změní data tak, že zabírají o třetinu více než původní soubor. Je tedy potřeba pamatovat na to, že pokud budete např. nahrávat 5MB fotku, musíte mít server nastavený tak, aby přijal alespoň 7MB v requestu.

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *

Tato stránka používá Akismet k omezení spamu. Podívejte se, jak vaše data z komentářů zpracováváme..