如何从base64数据字符串中保存PNG图片服务器端


211

我正在使用Nihilogic的“ Canvas2Image” JavaScript工具将画布图形转换为PNG图像。现在,我需要使用PHP将此工具生成的base64字符串转换为服务器上的实际PNG文件。

简而言之,我目前正在做的是使用Canvas2Image在客户端生成一个文件,然后检索base64编码的数据,并使用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
    }
});

此时,“ hidden.php”收到的数据块看起来像data:image / png; base64,iVBORw0KGgoAAAANSUhEUgAABE ...

从这一点开始,我很困惑。通过阅读,我相信应该使用PHP的imagecreatefromstring函数,但是我不确定如何从base64编码的字符串实际创建实际的PNG图像并将其存储在服务器上。请帮忙!


您需要解析它。您可以从那里提取图像类型,然后使用base64_decode并根据您的图像类型将该字符串保存在文件中
Constantin'July

@康斯坦丁,请您更具体吗?
安德烈·奥尼加

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

您可以从快照中发布完整的代码,直到发送数据为止,它对我不起作用。
Ofir Attia

Answers:


437

您需要从该字符串中提取base64图像数据,对其进行解码,然后可以将其保存到磁盘,因为它已经是png,所以不需要GD。

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

作为单线:

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

提取,解码和检查错误的有效方法是:

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

您的示例中有$ type。这个值应该是多少?
乔恩(Jon)

1
@乔恩$type,被分配一个值从爆炸取决于它的数据:图像/ JPG或数据:图像/ PNG等
drew010

我收到此错误:格式错误的utf-8字符可能编码错误,该怎么办?

@aldo可能发布一个包含代码和详细信息的新问题。仅基于该消息就可能很难说,而又看不到您的代码或不知道图像是如何编码的以及如何发送到脚本的。
drew010 '17

120

试试这个:

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

file_put_contents docs


4
我试过了,但是其中包括data:image/png;base64,会破坏文件。
Michael J. Calkins 2013年

2
@MichaelCalkins也为我破解了它。drew010的答案似乎是唯一始终有效的解决方案。
大卫·约翰·威尔士

24
如果包含,data:image/png;base64,则传递给的字符串base64_decode不是有效的base64。您只需要发送数据,drew010的答案就说明了这一点。这个答案没有什么坏的。您不能在不了解并期望它“正常工作”的情况下进行复制和粘贴。
Cypher 2014年

4
对于问题中提供的示例(它不是base64内容)不起作用,必须首先将其拆分(请参见接受的答案)。
本杰明·皮耶特

我的图像已成功保存。但是当我写图片的网址时,我看到一个空白图片。我确定我的dataURL是正确的,因为我使用window.open(dataURL)进行了测试。为什么空白图片?
partho

45

我必须用加号替换空格str_replace(' ', '+', $img);才能使其正常工作。

这是完整的代码

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

希望能有所帮助。


1
您的电话$img = str_replace(' ', '+', $img);对我有很大帮助,谢谢!为什么我必须先将空格转换为“ +”?
Sven

19

值得一说的是,讨论的主题已记录在RFC 2397中-“数据” URL方案(https://tools.ietf.org/html/rfc2397

因此,PHP具有处理此类数据的本机方式-“ data:流包装器”(http://php.net/manual/zh/wrappers.data.php

因此,您可以轻松地使用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
我喜欢这个答案,它应该有更多的选票,它使用的是本机函数,没有肮脏的自制数据操作!虽然,关于演出有什么想法吗?可以预见,它比preg_replace+ 快file_put_contents吗?
Bonswouar '18 -10-18

1
@Bonswouar谢谢。关于您的问题:我认为,确保您的应用程序没有性能问题的最佳方法是测量您在特定情况下的性能(基于环境,预期和允许的文件大小等)。我们可以尝试在此处使用代码并在答案中显示数字,但事实是,对于您的具体情况,它可能带来的危害大于积极的结果。最好总是自己确保(特别是如果我们正在谈论应用程序的性能关键部分)。
Vladimir Posvistelik '19年

11

那么您上面的解决方案取决于图像是jpeg文件。对于我使用的一般解决方案

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

11

采取@ dre010的想法,我将其扩展到了适用于任何图像类型的另一个功能:PNG,JPG,JPEG或GIF,并为文件名指定了唯一的名称。

该功能将图像数据和图像类型分开

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

基于drew010示例,我制作了一个易于理解的示例。

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

试试这个...

$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

一线性解决方案。

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

4

此代码对我有用,请检查以下代码:

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

此功能应该起作用。该参数具有photo参数,该参数包含base64字符串,还具有指向现有图像目录的路径(如果您已经具有要在保存新图像时取消链接的现有图像)。

 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

这很简单 :

假设您正在尝试在js框架,ajax请求或移动应用程序(客户端)中上传文件

  1. 首先,您发送一个包含base64编码字符串的数据属性。
  2. 在服务器端,您必须对其进行解码并将其保存在本地项目文件夹中。

这里如何使用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

如果要随机重命名图像,并将图像路径在数据库中存储为blob,并将图像本身存储在文件夹中,则此解决方案将为您提供帮助。您的网站用户可以根据需要存储任意数量的图像,出于安全考虑,这些图像将被随机重命名。

邮递区号

生成随机的varchars用作图像名称。

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

从image获取图像数据扩展名和base_64部分(在data:image / png; base64之后)。

$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已经对base64进行了公平处理->文件转换

我曾经用这种方式完成它:

$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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.