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

PhpJavascriptBase64Html5 Canvas

Php Problem Overview


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!

Php Solutions


Solution 1 - Php

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

Solution 2 - Php

Try this:

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

file_put_contents docs

Solution 3 - Php

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.

Solution 4 - Php

It worth to say that discussed topic is documented in RFC 2397 - The "data" URL scheme (https://www.rfc-editor.org/rfc/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 - Php

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

Solution 6 - Php

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 7 - Php

Total concerns:

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

// Extract base64 file for standard data
$fileBin = file_get_contents($data);
$mimeType = mime_content_type($data);

// Check allowed mime type
if ('image/png'==$mimeType) {
    file_put_contents('name.png', $fileBin);
}

> http://php.net/manual/en/wrappers.data.php > > http://php.net/manual/en/function.mime-content-type.php

Solution 8 - Php

One-linear solution.

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

Solution 9 - Php

This code works for me check below 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);
?>

Solution 10 - Php

based on drew010 example I made a working example for easy understanding.

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

Solution 11 - Php

try this...

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

Solution 12 - Php

PHP has already a fair treatment base64 -> file transform

I use to get it done coding this way:

$blob=$_POST['blob']; // base64 coming from an url, for example

//Now, let's save the image file:

file_put_contents('myfile.png',file_get_contents($blob));

Solution 13 - Php

Assuming you have filename in $filename and your base64encoded string in $testfile my oneliner:

file_put_contents($filename,base64_decode(explode(',', $testfile)[1]))

Solution 14 - Php

This function should work. this has the photo parameter that holds the base64 string and also path to an existing image directory should you already have an existing image you want to unlink while you save the new one.

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

Solution 15 - Php

It's simple :

Let's imagine that you are trying to upload a file within js framework, ajax request or mobile application (Client side)

  1. Firstly you send a data attribute that contains a base64 encoded string.
  2. In the server side you have to decode it and save it in a local project folder.

Here how to do it using 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));

?>

Solution 16 - Php

If you want to randomly rename images, and store both the image path on database as blob and the image itself on folders this solution will help you. Your website users can store as many images as they want while the images will be randomly renamed for security purposes.

Php code

Generate random varchars to use as image name.

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

Get image data extension and base_64 part (part after data:image/png;base64,) from 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. :)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndrei OnigaView Question on Stackoverflow
Solution 1 - Phpdrew010View Answer on Stackoverflow
Solution 2 - PhpSome GuyView Answer on Stackoverflow
Solution 3 - PhpBenView Answer on Stackoverflow
Solution 4 - PhpVladimir PosvistelikView Answer on Stackoverflow
Solution 5 - PhpPolloZenView Answer on Stackoverflow
Solution 6 - Phpdevil_ioView Answer on Stackoverflow
Solution 7 - PhpNick TsaiView Answer on Stackoverflow
Solution 8 - PhpPiotrView Answer on Stackoverflow
Solution 9 - PhpGauravbhai DaxiniView Answer on Stackoverflow
Solution 10 - Phpsanjeet bishtView Answer on Stackoverflow
Solution 11 - PhpPalineView Answer on Stackoverflow
Solution 12 - PhpPYKView Answer on Stackoverflow
Solution 13 - PhphisablikView Answer on Stackoverflow
Solution 14 - PhpSaviour DelaView Answer on Stackoverflow
Solution 15 - PhpMustapha GHLISSIView Answer on Stackoverflow
Solution 16 - PhpAnusionwu ChikelubaView Answer on Stackoverflow