Как сохранить изображение PNG на стороне сервера из строки данных base64


212

Я использую инструмент Canvas2Image от Nihilogic для преобразования рисунков холста в изображения PNG. Теперь мне нужно превратить те строки base64, которые генерирует этот инструмент, в настоящие файлы PNG на сервере с использованием PHP.

Короче говоря, сейчас я создаю файл на стороне клиента с помощью 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» получает блок данных, который выглядит как данные: image / png; base64, iVBORw0KGgoAAAANSUhEUgAABE ...

С этого момента я в значительной степени озадачен. Из того, что я прочитал, я считаю, что я должен использовать PHP- функцию imagecreatefromstring , но я не уверен, как на самом деле создать фактическое изображение PNG из строки в кодировке base64 и сохранить его на моем сервере. Пожалуйста, помогите!


Вы должны разобрать это. Вы можете извлечь тип изображения оттуда, а затем использовать base64_decode и сохранить эту строку в файле в соответствии с вашим типом изображения
Константин

@ Constantine Можете ли вы быть более конкретным, пожалуйста?
Андрей Онига

7
$ data = $ _REQUEST ['base64data']; $ image = explode ('base64,', $ data); file_put_contents ('img.png', base64_decode ($ image [1]));
Константин

Вы можете опубликовать полный код, начиная со снимка, и пока вы не отправите данные, он не работает для меня.
Офир Аттиа

Ответы:


437

Вам нужно извлечь данные изображения base64 из этой строки, декодировать их, а затем вы можете сохранить их на диск, вам не нужен GD, поскольку он уже является 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);

И как однострочник:

$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 в вашем примере. Каким должно быть это значение?
Джон

1
@Jon $typeполучает значение из разнесения , в зависимости от того, являются ли они данными: image / jpg или data: image / png и т. Д.
drew010

я получил эту ошибку: неправильно сформированные символы utf-8, возможно, неправильно закодированы, что мне делать?
Альдо

@aldo Вероятно, опубликуйте новый вопрос с кодом и деталями. Довольно сложно сказать, основываясь только на этом сообщении, не видя ваш код или не зная, как кодируется изображение и как оно отправляется в сценарий.
drew010

120

Попробуй это:

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

file_put_contents docs


4
Я пытался это, но это в том числе, data:image/png;base64,что нарушает файл.
Майкл Дж. Калкинс

2
@MichaelCalkins Ломает это и для меня тоже. Ответ drew010 кажется единственным решением, которое работает последовательно.
Дэвид Джон Валлийский

24
Если вы включаете data:image/png;base64,строку, то передаваемая строка не base64_decodeявляется действительной base64. Вам нужно только отправить данные, что иллюстрирует ответ drew010. С этим ответом ничего не нарушено. Вы не можете копировать и вставлять без понимания и ожидать, что это «просто сработает».
Cypher

4
Не работает для примера, приведенного в вопросе, который не является содержимым base64 и сначала должен быть разбит на части (см. Принятый ответ).
Бенджамин Пиетт

мое изображение было успешно сохранено. но когда я пишу URL изображения, я вижу пустое изображение. Я уверен, что мой dataURL правильный, потому что я проверял это с помощью window.open (dataURL). Почему пустое изображение?
Парто

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);мне очень помогла, спасибо! Почему я должен преобразовать пробел в "+" раньше?
Свен

19

Стоит сказать, что обсуждаемая тема задокументирована в RFC 2397 - Схема URL «данных» ( https://tools.ietf.org/html/rfc2397 ).

Из-за этого в PHP есть собственный способ обработки таких данных - «data: stream wrapper» ( http://php.net/manual/en/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?
Бонсуар

1
@ Бонсуар Спасибо. Что касается вашего вопроса: по моему мнению, лучший способ убедиться, что у вашего приложения нет проблем с производительностью, - это измерить его производительность в вашем конкретном случае (в зависимости от среды, ожидаемого и разрешенного размера файла и т. Д.). Мы могли бы попытаться поиграть с кодом здесь и показать цифры в ответе, но правда в том, что для вашего конкретного случая это может принести больше вреда, чем положительного результата. Всегда лучше убедиться в этом самостоятельно (особенно если речь идет о критически важных для приложения частях приложения).
Владимир Посвистелик

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

Однолинейное решение.

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

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

Этот код работает для меня, проверьте код ниже:

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

Если вы хотите случайным образом переименовать изображения и сохранить путь к изображению в базе данных в виде большого двоичного объекта и само изображение в папках, это решение поможет вам. Пользователи вашего сайта могут хранить столько изображений, сколько они хотят, в то время как изображения будут случайным образом переименованы в целях безопасности.

Код php

Генерация случайных вариантов для использования в качестве имени изображения.

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

Получить расширение данных изображения и часть base_64 (часть после данных: 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.