How to save a PNG image server-side, from a base64 data string

How to save a PNG image server-side, from a base64 data string

I’m using Nihilogic’s “Canvas2Image” JavaScript tool to convert canvas drawings to PNG images.
What I need now is to turn those base64 strings that this tool generates, into actual PNG files on the server, using PHP.
In short, what I’m currently doing is to generate a file on the client side using Canvas2Image, then retrieve the base64-encoded data and send it to the server using 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
}
});

At this point, “hidden.php” receives a data block that looks like data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABE…
From this point on, I’m pretty much stumped. From what I’ve read, I believe that I’m supposed to use PHP’s imagecreatefromstring function, but I’m not sure how to actually create an actual PNG image from the base64-encoded string and store it on my server.
Please aid!

Related:  Count immediate child div elements using jQuery

Solutions/Answers:

Solution 1:

You need to extract the base64 image data from that string, decode it and then you can save it to disk, you don’t need GD since it already is a 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);

And as a one-liner:

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

An efficient method for extracting, decoding, and checking for errors is:

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

Solution 2:

Try this:

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

file_put_contents docs

Solution 3:

I had to replace spaces with plus symbols str_replace(' ', '+', $img); to get this working.

Here is the full 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);

Hope that helps.

Related:  Unsigned Integer in Javascript

Solution 4:

It worth to say that discussed topic is documented in RFC 2397 – The “data” URL scheme (https://tools.ietf.org/html/rfc2397)

Because of this PHP has a native way to handle such data – “data: stream wrapper” (http://php.net/manual/en/wrappers.data.php)

So you can easily manipulate your data with PHP streams:

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

Solution 5:

Well your solution above depends on the image being a jpeg file. For a general solution i used

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

Solution 6:

Taken the @dre010 idea, I have extended it to another function that works with any image type: PNG, JPG, JPEG or GIF and gives a unique name to the filename

The function separate image data and image type

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