Bagaimana cara menyimpan sisi server gambar PNG, dari string data base64

212

Saya menggunakan alat JavaScript "Canvas2Image" Nihilogic untuk mengonversi gambar kanvas ke gambar PNG. Yang saya butuhkan sekarang adalah untuk mengubah string base64 yang dihasilkan alat ini, menjadi file PNG aktual di server, menggunakan PHP.

Singkatnya, apa yang saya lakukan saat ini adalah membuat file di sisi klien menggunakan Canvas2Image, kemudian mengambil data yang di-encode base64 dan mengirimkannya ke server menggunakan 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
    }
});

Pada titik ini, "hidden.php" menerima blok data yang terlihat seperti data: image / png; base64, iVBORw0KGgoAAAANSUhEUgAABE ...

Mulai saat ini, saya cukup bingung. Dari apa yang saya baca, saya percaya bahwa saya seharusnya menggunakan fungsi imagecreatefromstring PHP , tapi saya tidak yakin bagaimana benar-benar membuat gambar PNG yang sebenarnya dari string yang dikodekan base64 dan menyimpannya di server saya. Tolong bantu!

Andrei Oniga
sumber
Anda perlu menguraikannya. Anda dapat mengekstraksi jenis gambar dari sana dan kemudian menggunakan base64_decode dan menyimpan string itu dalam file dengan jenis gambar Anda
Constantin
@Constantine Bisakah Anda lebih spesifik?
Andrei Oniga
7
$ data = $ _REQUEST ['base64data']; $ image = explode ('base64,', $ data); file_put_contents ('img.png', base64_decode ($ image [1]));
Constantin
Anda dapat memposting kode lengkap, dari snapshot dan hingga Anda mengirim data, itu tidak berfungsi untuk saya.
Ofir Attia

Jawaban:

437

Anda perlu mengekstrak data gambar base64 dari string itu, mendekodekannya dan kemudian Anda dapat menyimpannya ke disk, Anda tidak perlu GD karena sudah 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);

Dan sebagai one-liner:

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

Metode yang efisien untuk mengekstraksi, decoding, dan memeriksa kesalahan adalah:

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);
drew010
sumber
Anda memiliki $ type dalam contoh Anda. Apa nilai itu seharusnya?
Jon
1
@ Jon $typemendapat nilai dari ledakan, tergantung pada apakah itu data: image / jpg atau data: image / png dll.
drew010
saya mendapatkan kesalahan ini: salah utf-8 karakter mungkin salah dikodekan apa yang harus saya lakukan?
aldo
@aldo Mungkin memposting pertanyaan baru dengan kode dan detail. Sangat mustahil untuk mengatakan berdasarkan hanya pada pesan itu dan tanpa melihat kode Anda atau mengetahui bagaimana gambar dikodekan dan bagaimana itu dikirim ke skrip.
drew010
120

Coba ini:

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

file_put_contents docs

Beberapa pria
sumber
4
Saya mencoba ini tetapi termasuk data:image/png;base64,yang memecah file.
Michael J. Calkins
2
@MichaelCalkins Memberi istirahat untukku juga. jawaban drew010 tampaknya satu-satunya solusi yang bekerja secara konsisten.
David John Welsh
24
Jika Anda memasukkan data:image/png;base64,string yang Anda lewati base64_decodetidak base64 valid. Anda hanya perlu mengirim data, itulah yang menggambarkan jawaban drew010. Tidak ada yang rusak dengan jawaban ini. Anda tidak dapat menyalin dan menempel tanpa memahami dan mengharapkannya "berfungsi".
Cypher
4
Tidak berfungsi untuk contoh yang disediakan dalam pertanyaan, yang bukan merupakan konten base64, dan pertama-tama harus dibagi menjadi beberapa bagian (lihat jawaban yang diterima).
Benjamin Piette
gambar saya telah berhasil disimpan. tetapi ketika saya menulis url gambar saya melihat gambar kosong. Saya yakin bahwa dataURL saya benar, karena saya mengujinya menggunakan window.open (dataURL). Mengapa gambar kosong?
Partho
45

Saya harus mengganti spasi dengan simbol plus str_replace(' ', '+', $img); untuk membuatnya berfungsi.

Ini kode lengkapnya

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

Semoga itu bisa membantu.

Ben
sumber
1
Baris Anda $img = str_replace(' ', '+', $img);banyak membantu saya, terima kasih! Mengapa saya harus mengubah spasi menjadi "+" sebelumnya?
Sven
19

Layak untuk mengatakan bahwa topik yang dibahas didokumentasikan dalam RFC 2397 - Skema URL "data" ( https://tools.ietf.org/html/rfc2397 )

Karena PHP ini memiliki cara asli untuk menangani data seperti itu - "data: stream wrapper" ( http://php.net/manual/en/wrappers.data.php )

Jadi Anda dapat dengan mudah memanipulasi data Anda dengan aliran 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);
Vladimir Posvistelik
sumber
2
Saya suka jawaban ini, seharusnya memiliki lebih banyak suara, menggunakan fungsi asli, tidak ada manipulasi data buatan sendiri yang kotor! Meskipun, ada ide tentang pertunjukan? Apakah itu, seperti yang diharapkan, lebih cepat dari preg_replace+ file_put_contents?
Bonswouar
1
@Bonswouar Terima kasih. Mengenai pertanyaan Anda: menurut saya cara terbaik untuk memastikan bahwa aplikasi Anda tidak memiliki masalah kinerja adalah dengan mengukur kinerjanya dalam kasus khusus Anda (berdasarkan lingkungan, ukuran file yang diharapkan dan diizinkan, dan sebagainya). Kami dapat mencoba bermain dengan kode di sini dan menunjukkan angka dalam jawabannya, tetapi kenyataannya adalah untuk kasus Anda yang sebenarnya, hal itu dapat membawa lebih banyak kerugian daripada hasil positif. Itu selalu lebih baik untuk memastikan sendiri (terutama jika kita berbicara bagian kritis kinerja dari aplikasi).
Vladimir Posvistelik
11

Nah solusi Anda di atas tergantung pada gambar menjadi file jpeg. Untuk solusi umum yang saya gunakan

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

Diambil ide @ dre010, saya telah memperluasnya ke fungsi lain yang bekerja dengan semua tipe gambar: PNG, JPG, JPEG atau GIF dan memberikan nama unik ke nama file

Fungsi memisahkan data gambar dan tipe gambar

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);
}
PolloZen
sumber
5

Solusi satu linier.

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

berdasarkan contoh drew010 saya membuat contoh untuk memudahkan pemahaman.

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; 
}
sanjeet bisht
sumber
4

coba ini...

$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));
Paline
sumber
4

Kode ini berfungsi untuk saya, periksa kode di bawah ini:

<?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);
?>
gauravbhai daxini
sumber
0

Fungsi ini seharusnya berfungsi. ini memiliki parameter foto yang menahan string base64 dan juga path ke direktori gambar yang sudah ada seandainya Anda sudah memiliki gambar yang sudah ada yang ingin Anda batalkan tautannya saat menyimpan yang baru.

 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
        }
    }
}
Juruselamat Dela
sumber
0

Itu mudah :

Bayangkan Anda mencoba mengunggah file ke dalam kerangka js, permintaan ajax, atau aplikasi seluler (sisi Klien)

  1. Pertama Anda mengirim atribut data yang berisi string yang disandikan base64.
  2. Di sisi server Anda harus men-decode dan menyimpannya di folder proyek lokal.

Berikut cara melakukannya menggunakan 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));

?>
MUSTAPHA GHLISSI
sumber
0

Jika Anda ingin mengubah nama gambar secara acak, dan menyimpan jalur gambar pada basis data sebagai gumpalan dan gambar itu sendiri di folder solusi ini akan membantu Anda. Pengguna situs web Anda dapat menyimpan gambar sebanyak yang mereka inginkan sementara gambar akan diganti secara acak untuk tujuan keamanan.

Kode php

Hasilkan varchars acak untuk digunakan sebagai nama gambar.

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

Dapatkan ekstensi data gambar dan bagian base_64 (bagian setelah data: image / png; base64,) dari gambar.

$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. :)
Chikeluba Anusionwu
sumber
0

PHP sudah memiliki base64 perlakuan yang adil -> transformasi file

Saya menggunakan untuk menyelesaikannya dengan cara ini:

$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
PYK
sumber