Search code examples
phpjavascriptbase64html5-canvas

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


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!


Solution

  • 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 = str_replace( ' ', '+', $data );
        $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);