Як зберегти зображення PNG на стороні сервера із рядка даних base64


212

Я використовую інструмент JavaScript "Canvas2Image" Nihilogic для перетворення малюнків полотна в зображення PNG. Що мені зараз потрібно - це перетворити ці рядки base64, які створює цей інструмент, у фактичні файли PNG на сервері, використовуючи PHP.

Коротше кажучи, те, що я зараз роблю, - це генерувати файл на стороні клієнта за допомогою Canvas2Image, а потім отримувати кодовані базою 64 дані та відправляти їх на сервер за допомогою 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, iVBORw0KGgoAAAANANhEUgAABE ...

З цього моменту я досить сильно тупнув. З того, що я прочитав, я вважаю, що я повинен використовувати функцію imagecreatefromstring PHP , але я не впевнений, як насправді створити фактичне зображення PNG з кодованого рядка base64 і зберігати його на своєму сервері. Будь ласка, допоможіть!


вам потрібно його розібрати. ви можете витягти звідти тип зображення, а потім використовувати base64_decode і зберегти цей рядок у файлі за вашим типом зображення
Константин

@Constantine Ви можете бути більш конкретними, будь ласка?
Андрій Онига

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

Ви можете опублікувати повний код, починаючи із знімка, і поки ви не надішлете дані, він не працює для мене.
Офір Аттіа

Відповіді:


437

Вам потрібно витягнути базові дані image64 з цього рядка, розшифрувати їх, а потім ви можете зберегти їх на диску, 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. Якою має бути ця цінність?
Jon

1
@Jon $typeотримує присвоєне значення від вибуху, залежно від того, чи це дані: image / jpg або дані: image / png тощо
drew010

У мене виникла помилка: неправильно зафіксовані символи utf-8, можливо, неправильно закодовані, що мені робити?
альдо

@aldo Ймовірно, опублікуйте нове запитання з кодом та деталями. Досить неможливо сказати, базуючись саме на цьому повідомленні та не бачачи свого коду чи знаючи, як закодовано зображення та як воно надсилається до сценарію.
drew010

120

Спробуйте це:

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

file_put_contents Документи


4
Я спробував це, але це включає в себе те, data:image/png;base64,що порушує файл.
Майкл Дж. Калкінс

2
@MichaelCalkins Порушує це і для мене. Відповідь drew010 видається єдиним рішенням, яке працює послідовно.
Девід Джон Уельс

24
Якщо ви включаєте, data:image/png;base64,то рядок, який ви передаєте base64_decode, не є дійсним base64. Вам потрібно лише надіслати дані, що ілюструє відповідь drew010. З цією відповіддю нічого не порушено. Ви не можете скопіювати та вставити, не розуміючи, і очікуйте, що це "просто працює".
Cypher

4
Не працює на прикладі, наведеному у запитанні, який не є базовим вмістом64, і спочатку його потрібно розділити на частини (див. Прийняту відповідь).
Бенджамін Піет

моє зображення успішно збережено. але коли я пишу URL-адресу зображення, я бачу порожнє зображення. Я впевнений, що мої даніURL вірні, тому що я перевірив це за допомогою 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);мені дуже допомогла, дякую! Чому я повинен перетворити пробіл у "+" раніше?
Свен

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
@Bonswouar Дякую Що стосується вашого питання: на мою думку, найкращим способом забезпечити, щоб у вашої програми не було проблем з продуктивністю, було б виміряти її ефективність у вашому конкретному випадку (виходячи з середовища, очікуваного та дозволеного розміру файлу тощо). Ми можемо спробувати пограти з кодом тут і показати цифри у відповіді, але правда полягає в тому, що для вашого точного випадку це може принести більше шкоди, ніж позитивного результату. Завжди краще переконатися в цьому самостійно (особливо якщо ми говоримо про важливі для програми частини програми).
Володимир Посвістелік

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

Ця функція повинна працювати. тут є параметр фотографії, який містить рядок 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.