Speichern eines serverseitigen PNG-Bilds aus einer base64-Datenzeichenfolge

212

Ich verwende das JavaScript-Tool "Canvas2Image" von Nihilogic, um Leinwandzeichnungen in PNG-Bilder zu konvertieren. Was ich jetzt brauche, ist, die von diesem Tool generierten base64-Zeichenfolgen mithilfe von PHP in tatsächliche PNG-Dateien auf dem Server umzuwandeln.

Kurz gesagt, ich generiere derzeit eine Datei auf der Clientseite mit Canvas2Image, rufe dann die base64-codierten Daten ab und sende sie mit AJAX an den Server:

// 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
    }
});

Zu diesem Zeitpunkt empfängt "hidden.php" einen Datenblock, der wie Daten aussieht : image / png; base64, iVBORw0KGgoAAAANSUhEUgAABE ...

Von diesem Punkt an bin ich ziemlich ratlos. Nach dem , was ich gelesen habe, glaube ich, dass ich die Imagecreatefromstring- Funktion von PHP verwenden soll , bin mir aber nicht sicher, wie ich tatsächlich ein tatsächliches PNG-Image aus der base64-codierten Zeichenfolge erstellen und auf meinem Server speichern soll. Bitte helfen Sie!

Andrei Oniga
quelle
Sie müssen es analysieren. Sie können den Bildtyp von dort extrahieren und dann base64_decode verwenden und diese Zeichenfolge in einer Datei nach Ihrem Bildtyp speichern
Constantin
@Constantine Können Sie bitte genauer sein?
Andrei Oniga
7
$ data = $ _REQUEST ['base64data']; $ image = explode ('base64,', $ data); file_put_contents ('img.png', base64_decode ($ image [1]));
Constantin
Sie können den vollständigen Code aus dem Schnappschuss veröffentlichen und bis Sie die Daten senden, funktioniert er bei mir nicht.
Ofir Attia

Antworten:

437

Sie müssen die base64-Bilddaten aus dieser Zeichenfolge extrahieren, dekodieren und dann auf der Festplatte speichern. Sie benötigen GD nicht, da es sich bereits um ein PNG handelt.

$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);

Und als Einzeiler:

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

Eine effiziente Methode zum Extrahieren, Dekodieren und Überprüfen auf Fehler ist:

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);
zog010
quelle
Sie haben $ type in Ihrem Beispiel. Was soll dieser Wert sein?
Jon
1
@ Jon $typewird ein Wert von der Explosion zugewiesen, abhängig davon, ob es Daten sind: Bild / JPG oder Daten: Bild / PNG usw.
draw010
Ich habe diesen Fehler erhalten: fehlerhafte utf-8-Zeichen möglicherweise falsch codiert Was soll ich tun?
Aldo
@aldo Poste wahrscheinlich eine neue Frage mit Code und Details. Es ist ziemlich unmöglich, nur anhand dieser Nachricht zu sagen, ohne Ihren Code zu sehen oder zu wissen, wie das Bild codiert und wie es an das Skript gesendet wird.
Draw010
120

Versuche dies:

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

file_put_contents docs

Irgendein Typ
quelle
4
Ich habe es versucht, aber es enthält auch das, data:image/png;base64,was die Datei bricht.
Michael J. Calkins
2
@ MichaelCalkins Bricht es auch für mich. Die Antwort von draw010 scheint die einzige Lösung zu sein, die konsistent funktioniert.
David John Welsh
24
Wenn Sie data:image/png;base64,die Zeichenfolge einschließen, ist die Zeichenfolge, an die Sie übergeben, base64_decodenicht gültig. Sie müssen nur die Daten senden, wie die Antwort von draw010 zeigt. An dieser Antwort ist nichts kaputt. Sie können nicht kopieren und einfügen, ohne es zu verstehen, und erwarten, dass es "nur funktioniert".
Cypher
4
Funktioniert nicht für das in der Frage angegebene Beispiel, bei dem es sich nicht um einen base64-Inhalt handelt, und muss zuerst in Teile geteilt werden (siehe die akzeptierte Antwort).
Benjamin Piette
Mein Bild wurde erfolgreich gespeichert. aber wenn ich URL des Bildes schreibe, sehe ich ein leeres Bild. Ich bin sicher, dass meine dataURL korrekt ist, da ich dies mit window.open (dataURL) getestet habe. Warum ein leeres Bild?
Partho
45

Ich musste Leerzeichen durch Pluszeichen ersetzen str_replace(' ', '+', $img);, damit dies funktioniert.

Hier ist der vollständige Code

$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);

Hoffentlich hilft das.

Ben
quelle
1
Ihre Linie $img = str_replace(' ', '+', $img);hat mir sehr geholfen, danke! Warum muss ich das Leerzeichen vorher in "+" konvertieren?
Sven
19

Es ist erwähnenswert, dass das diskutierte Thema in RFC 2397 - Das URL-Schema "Daten" ( https://tools.ietf.org/html/rfc2397 ) dokumentiert ist.

Aus diesem Grund hat PHP eine native Methode, um mit solchen Daten umzugehen - "data: stream wrapper" ( http://php.net/manual/en/wrappers.data.php )

So können Sie Ihre Daten einfach mit PHP-Streams bearbeiten:

$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);
Vladimir Posvistelik
quelle
2
Ich mag diese Antwort, sie sollte mehr Stimmen haben, sie verwendet native Funktionen, keine schmutzige hausgemachte Datenmanipulation! Obwohl, eine Idee über Aufführungen? Ist es, wie zu erwarten, schneller als preg_replace+ file_put_contents?
Bonswouar
1
@ Bonswouar Danke. Zu Ihrer Frage: Meiner Meinung nach besteht der beste Weg, um sicherzustellen, dass Ihre Anwendung keine Leistungsprobleme aufweist, darin, die Leistung in Ihrem speziellen Fall zu messen (basierend auf der Umgebung, der erwarteten und zulässigen Dateigröße usw.). Wir könnten versuchen, hier mit Code zu spielen und Zahlen in der Antwort anzuzeigen, aber die Wahrheit ist, dass es für Ihren genauen Fall mehr Schaden als positives Ergebnis bringen könnte. Es ist immer besser, sich selbst zu vergewissern (insbesondere, wenn es sich um leistungskritische Teile der App handelt).
Vladimir Posvistelik
11

Nun, Ihre obige Lösung hängt davon ab, ob das Bild eine JPEG-Datei ist. Für eine allgemeine Lösung habe ich verwendet

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

Ausgehend von der @ dre010-Idee habe ich sie auf eine andere Funktion erweitert, die mit jedem Bildtyp funktioniert: PNG, JPG, JPEG oder GIF und dem Dateinamen einen eindeutigen Namen gibt

Die Funktion trennt Bilddaten und Bildtyp

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);
}
PolloZen
quelle
5

Einlineare Lösung.

$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]));
Piotr
quelle
5

basierend auf dem Beispiel draw010 habe ich ein Arbeitsbeispiel zum leichteren Verständnis erstellt.

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; 
}
Sanjeet Bisht
quelle
4

Versuche dies...

$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));
Paline
quelle
4

Dieser Code funktioniert für mich. Überprüfen Sie den folgenden Code:

<?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);
?>
gauravbhai daxini
quelle
0

Diese Funktion sollte funktionieren. Dies hat den Fotoparameter, der die base64-Zeichenfolge enthält, sowie den Pfad zu einem vorhandenen Bildverzeichnis, falls Sie bereits ein vorhandenes Bild haben, dessen Verknüpfung Sie beim Speichern des neuen Bilds aufheben möchten.

 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
        }
    }
}
Retter Dela
quelle
0

Es ist einfach :

Stellen Sie sich vor, Sie versuchen, eine Datei innerhalb des JS-Frameworks, der Ajax-Anfrage oder der mobilen Anwendung (Client-Seite) hochzuladen.

  1. Zunächst senden Sie ein Datenattribut, das eine Base64-codierte Zeichenfolge enthält.
  2. Auf der Serverseite müssen Sie es dekodieren und in einem lokalen Projektordner speichern.

Hier erfahren Sie, wie es mit PHP geht

<?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));

?>
MUSTAPHA GHLISSI
quelle
0

Wenn Sie Bilder nach dem Zufallsprinzip umbenennen und sowohl den Bildpfad in der Datenbank als Blob als auch das Bild selbst in Ordnern speichern möchten, hilft Ihnen diese Lösung. Die Benutzer Ihrer Website können so viele Bilder speichern, wie sie möchten, während die Bilder aus Sicherheitsgründen zufällig umbenannt werden.

PHP-Code

Generieren Sie zufällige Varchars, die als Bildname verwendet werden sollen.

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).

Holen Sie sich die Bilddatenerweiterung und den base_64-Teil (Teil nach den Daten: image / png; base64,) aus dem Image.

$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. :)
Chikeluba Anusionwu
quelle
0

PHP hat bereits eine faire Behandlung base64 -> Dateitransformation

Ich benutze es, um es auf folgende Weise zu erledigen:

$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
PYK
quelle