Come salvare un'immagine PNG sul lato server, da una stringa di dati base64


212

Sto usando lo strumento JavaScript "Canvas2Image" di Nihilogic per convertire i disegni su tela in immagini PNG. Ciò di cui ho bisogno ora è trasformare quelle stringhe base64 che questo strumento genera, in veri e propri file PNG sul server, usando PHP.

In breve, quello che sto facendo attualmente è generare un file sul lato client usando Canvas2Image, quindi recuperare i dati con codifica base64 e inviarlo al server usando AJAX:

// Generate the image file
var image = Canvas2Image.saveAsPNG(canvas, true);   

image.id = "canvasimage";
canvas.parentNode.replaceChild(image, canvas);

var url = 'hidden.php',
data = $('#canvasimage').attr('src');

$.ajax({ 
    type: "POST", 
    url: url,
    dataType: 'text',
    data: {
        base64data : data
    }
});

A questo punto, "hidden.php" riceve un blocco di dati che assomiglia a dati: image / png; base64, iVBORw0KGgoAAAANSUhEUgAABE ...

Da questo punto in poi, sono praticamente sconcertato. Da quello che ho letto, credo che dovrei usare la funzione imagecreatefromstring di PHP , ma non sono sicuro di come effettivamente creare un'immagine PNG reale dalla stringa codificata in base64 e archiviarla sul mio server. Per favore aiuto!


devi analizzarlo. puoi estrarre il tipo di immagine da lì e quindi utilizzare base64_decode e salvare quella stringa in un file in base al tipo di immagine
Constantin

@Constantine Puoi essere più specifico, per favore?
Andrei Oniga,

7
$ data = $ _REQUEST ['base64data']; $ image = explode ('base64,', $ data); file_put_contents ('img.png', base64_decode ($ image [1]));
Constantin,

puoi pubblicare il codice completo, dall'istantanea e fino a quando non invii i dati, non funziona per me.
Ofir Attia,

Risposte:


437

Devi estrarre i dati dell'immagine base64 da quella stringa, decodificarli e quindi puoi salvarli su disco, non hai bisogno di GD poiché è già un png.

$data = 'data:image/png;base64,AAAFBfj42Pj4';

list($type, $data) = explode(';', $data);
list(, $data)      = explode(',', $data);
$data = base64_decode($data);

file_put_contents('/tmp/image.png', $data);

E come one-liner:

$data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data));

Un metodo efficiente per l'estrazione, la decodifica e il controllo degli errori è:

if (preg_match('/^data:image\/(\w+);base64,/', $data, $type)) {
    $data = substr($data, strpos($data, ',') + 1);
    $type = strtolower($type[1]); // jpg, png, gif

    if (!in_array($type, [ 'jpg', 'jpeg', 'gif', 'png' ])) {
        throw new \Exception('invalid image type');
    }

    $data = base64_decode($data);

    if ($data === false) {
        throw new \Exception('base64_decode failed');
    }
} else {
    throw new \Exception('did not match data URI with image data');
}

file_put_contents("img.{$type}", $data);

Hai $ type nel tuo esempio. Quale dovrebbe essere quel valore?
Jon,

1
A @Jon $typeviene assegnato un valore dall'esplosione, a seconda che si tratti di dati: immagine / jpg o dati: immagine / png ecc.
drew010

ho ricevuto questo errore: caratteri utf-8 malformati probabilmente codificati in modo errato cosa devo fare?
aldo,

@aldo Probabilmente pubblica una nuova domanda con codice e dettagli. Abbastanza impossibile da dire basato solo su quel messaggio e senza vedere il tuo codice o sapere come l'immagine è codificata e come viene inviata allo script.
drew010,

120

Prova questo:

file_put_contents('img.png', base64_decode($base64string));

file_put_contents documenti


4
Ho provato questo, ma è incluso quello data:image/png;base64,che rompe il file.
Michael J. Calkins,

2
@MichaelCalkins Lo rompe anche per me. La risposta di drew010 sembra l'unica soluzione che funzioni in modo coerente.
David John Welsh,

24
Se stai includendo la data:image/png;base64,stringa a cui stai passando base64_decodenon è base64 valida. Devi solo inviare i dati, che è ciò che illustra la risposta di drew010. Non c'è nulla di rotto in questa risposta. Non è possibile copiare e incollare senza capire e aspettarsi che "funzioni".
Cypher

4
Non funziona per l'esempio fornito nella domanda, che non è un contenuto base64, e prima deve essere diviso in pezzi (vedi la risposta accettata).
Benjamin Piette,

la mia immagine è stata salvata con successo. ma quando scrivo l'URL dell'immagine vedo un'immagine vuota. Sono sicuro che il mio dataURL sia corretto, perché l'ho testato usando window.open (dataURL). Perché un'immagine vuota?
partho,

45

Ho dovuto sostituire gli spazi con simboli più str_replace(' ', '+', $img);per farlo funzionare.

Ecco il codice completo

$img = $_POST['img']; // Your data 'data:image/png;base64,AAAFBfj42Pj4';
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
file_put_contents('/tmp/image.png', $data);

Spero che aiuti.


1
La tua linea $img = str_replace(' ', '+', $img);mi ha aiutato molto, grazie! Perché prima devo convertire lo spazio in "+"?
Sven

19

Vale la pena di dire che l'argomento discusso è documentato in RFC 2397 - Lo schema URL "dati" ( https://tools.ietf.org/html/rfc2397 )

Per questo motivo PHP ha un modo nativo di gestire tali dati: "data: stream wrapper" ( http://php.net/manual/en/wrappers.data.php )

Quindi puoi facilmente manipolare i tuoi dati con flussi PHP:

$data = 'data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7';

$source = fopen($data, 'r');
$destination = fopen('image.gif', 'w');

stream_copy_to_stream($source, $destination);

fclose($source);
fclose($destination);

2
Mi piace questa risposta, dovrebbe avere più voti, sta usando funzioni native, nessuna manipolazione sporca dei dati fatti in casa! Anche se, qualche idea sulle esibizioni? Come ci si potrebbe aspettare, è più veloce di preg_replace+ file_put_contents?
Bonswouar,

1
@Bonswouar Grazie. Per quanto riguarda la tua domanda: a mio avviso il modo migliore per garantire che la tua applicazione non abbia problemi di prestazioni sarebbe quello di misurare le sue prestazioni nel tuo caso particolare (in base all'ambiente, alle dimensioni previste e consentite dei file e così via). Potremmo provare a giocare con il codice qui e mostrare i numeri nella risposta, ma la verità è che per il tuo caso esatto potrebbe portare più danni che esiti positivi. È sempre meglio accertarsi da soli (soprattutto se parliamo di parti dell'app per le prestazioni critiche).
Vladimir Posvistelik

11

Bene, la tua soluzione sopra dipende dal fatto che l'immagine sia un file jpeg. Per una soluzione generale che ho usato

$img = $_POST['image'];
$img = substr(explode(";",$img)[1], 7);
file_put_contents('img.png', base64_decode($img));

11

Preso l'idea @ dre010, l'ho esteso ad un'altra funzione che funziona con qualsiasi tipo di immagine: PNG, JPG, JPEG o GIF e dà un nome univoco al nome del file

La funzione separa i dati e il tipo di immagine

function base64ToImage($imageData){
    $data = 'data:image/png;base64,AAAFBfj42Pj4';
    list($type, $imageData) = explode(';', $imageData);
    list(,$extension) = explode('/',$type);
    list(,$imageData)      = explode(',', $imageData);
    $fileName = uniqid().'.'.$extension;
    $imageData = base64_decode($imageData);
    file_put_contents($fileName, $imageData);
}


5

Una soluzione lineare.

$base64string = 'data:image/png;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7';
file_put_contents('img.png', base64_decode(explode(',',$base64string)[1]));

5

basato sull'esempio di drew010 ho fatto un esempio funzionante per una facile comprensione.

imagesaver("data:image/jpeg;base64,/9j/4AAQSkZJ"); //use full base64 data 

function imagesaver($image_data){

    list($type, $data) = explode(';', $image_data); // exploding data for later checking and validating 

    if (preg_match('/^data:image\/(\w+);base64,/', $image_data, $type)) {
        $data = substr($data, strpos($data, ',') + 1);
        $type = strtolower($type[1]); // jpg, png, gif

        if (!in_array($type, [ 'jpg', 'jpeg', 'gif', 'png' ])) {
            throw new \Exception('invalid image type');
        }

        $data = base64_decode($data);

        if ($data === false) {
            throw new \Exception('base64_decode failed');
        }
    } else {
        throw new \Exception('did not match data URI with image data');
    }

    $fullname = time().$type;

    if(file_put_contents($fullname, $data)){
        $result = $fullname;
    }else{
        $result =  "error";
    }
    /* it will return image name if image is saved successfully 
    or it will return error on failing to save image. */
    return $result; 
}

4

prova questo...

$file = $_POST['file']; //your data in base64 'data:image/png....';
$img = str_replace('data:image/png;base64,', '', $file);
file_put_contents('img/imag.png', base64_decode($img));

4

Questo codice funziona per me controlla sotto il codice:

<?php
define('UPLOAD_DIR', 'images/');
$image_parts = explode(";base64,", $_POST['image']);
$image_type_aux = explode("image/", $image_parts[0]);
$image_type = $image_type_aux[1];
$image_base64 = base64_decode($image_parts[1]);
$file = UPLOAD_DIR . uniqid() . '.png';
file_put_contents($file, $image_base64);
?>

0

Questa funzione dovrebbe funzionare. questo ha il parametro foto che contiene la stringa base64 e anche il percorso di una directory di immagine esistente se si dispone già di un'immagine esistente che si desidera scollegare mentre si salva quella nuova.

 public function convertBase64ToImage($photo = null, $path = null) {
    if (!empty($photo)) {
        $photo = str_replace('data:image/png;base64,', '', $photo);
        $photo = str_replace(' ', '+', $photo);
        $photo = str_replace('data:image/jpeg;base64,', '', $photo);
        $photo = str_replace('data:image/gif;base64,', '', $photo);
        $entry = base64_decode($photo);
        $image = imagecreatefromstring($entry);

        $fileName = time() . ".jpeg";
        $directory = "uploads/customer/" . $fileName;

        header('Content-type:image/jpeg');

        if (!empty($path)) {
            if (file_exists($path)) {
                unlink($path);
            }
        }

        $saveImage = imagejpeg($image, $directory);

        imagedestroy($image);

        if ($saveImage) {
            return $fileName;
        } else {
            return false; // image not saved
        }
    }
}

0

È semplice :

Immaginiamo che stai cercando di caricare un file all'interno di js framework, ajax request o applicazione mobile (lato client)

  1. Innanzitutto si invia un attributo di dati che contiene una stringa codificata base64.
  2. Sul lato server devi decodificarlo e salvarlo in una cartella di progetto locale.

Ecco come farlo usando PHP

<?php 

$base64String = "kfezyufgzefhzefjizjfzfzefzefhuze"; // I put a static base64 string, you can implement you special code to retrieve the data received via the request.

$filePath = "/MyProject/public/uploads/img/test.png";

file_put_contents($filePath, base64_decode($base64String));

?>

0

Se si desidera rinominare casualmente le immagini e archiviare sia il percorso dell'immagine nel database come BLOB sia l'immagine stessa nelle cartelle, questa soluzione ti aiuterà. Gli utenti del tuo sito Web possono archiviare tutte le immagini che desiderano, mentre le immagini verranno rinominate casualmente per motivi di sicurezza.

Codice php

Genera varchar casuali da utilizzare come nome dell'immagine.

function genhash($strlen) {
        $h_len = $len;
        $cstrong = TRUE;
        $sslkey = openssl_random_pseudo_bytes($h_len, $cstrong);
        return bin2hex($sslkey);
}
$randName = genhash(3); 
#You can increase or decrease length of the image name (1, 2, 3 or more).

Ottieni l'estensione dei dati immagine e parte base_64 (parte dopo i dati: immagine / png; base64,) dall'immagine.

$pos  = strpos($base64_img, ';');
$imgExten = explode('/', substr($base64_img, 0, $pos))[1];
$extens = ['jpg', 'jpe', 'jpeg', 'jfif', 'png', 'bmp', 'dib', 'gif' ];

if(in_array($imgExten, $extens)) {

   $imgNewName = $randName. '.' . $imgExten;
   $filepath = "resources/images/govdoc/".$imgNewName;
   $fileP = fopen($filepath, 'wb');
   $imgCont = explode(',', $base64_img);
   fwrite($fileP, base64_decode($imgCont[1]));
   fclose($fileP);

}

# => $filepath <= This path will be stored as blob type in database.
# base64_decoded images will be written in folder too.

# Please don't forget to up vote if you like my solution. :)

0

PHP ha già un trattamento equo base64 -> trasformazione file

Uso per farlo usando questo modo:

$blob=$_POST['blob']; // base64 coming from an url, for example
$blob=file_get_contents($blob);
$fh=fopen("myfile.png",'w'); // be aware, it'll overwrite!
fwrite($fh,$blob);
fclose($fh);
echo '<img src=myfile.png>'; // just for the check
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.