วิธีบันทึก 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" ได้รับบล็อกข้อมูลที่ดูเหมือนdata: image / png; base64, iVBORw0KGgoAAAANSUhEUgAABE ...

จากจุดนี้ไปฉันก็นิ่งงันมาก จากสิ่งที่ฉันได้อ่านฉันเชื่อว่าฉันควรจะใช้ฟังก์ชั่นimagecreatefromstringของ PHP แต่ฉันไม่แน่ใจว่าจะสร้างภาพ PNG จริงจากสตริงที่เข้ารหัสแบบ 64 และเก็บไว้บนเซิร์ฟเวอร์ของฉันได้อย่างไร โปรดช่วยด้วย!


คุณต้องแยกมัน คุณสามารถแยกประเภทภาพออกจากที่นั่นแล้วใช้ base64_decode และบันทึกสตริงนั้นในไฟล์ตามประเภทรูปภาพของคุณ
Constantin

@ คอนสแตนตินคุณจะเจาะจงมากขึ้นได้ไหม
Andrei Oniga

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

คุณสามารถโพสต์รหัสเต็มจากภาพรวมและจนกว่าคุณจะส่งข้อมูลมันไม่ทำงานสำหรับฉัน
Ofir Attia

คำตอบ:


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 ในตัวอย่างของคุณ คุณค่านั้นควรเป็นอย่างไร?
Jon

1
@ จอน$typeได้รับการกำหนดค่าจากการระเบิดขึ้นอยู่กับว่าเป็นข้อมูล: image / jpg หรือข้อมูล: image / png เป็นต้น
drew010

ฉันได้รับข้อผิดพลาดนี้: อักขระ utf-8 ที่มีรูปแบบไม่ถูกต้องอาจเข้ารหัสอย่างไม่ถูกต้องฉันควรทำอย่างไร
aldo

@aldo อาจโพสต์คำถามใหม่ด้วยรหัสและรายละเอียด ค่อนข้างเป็นไปไม่ได้ที่จะพูดตามข้อความนั้นและไม่เห็นรหัสของคุณหรือรู้ว่าภาพนั้นถูกเข้ารหัสอย่างไรและมันถูกส่งไปยังสคริปต์อย่างไร
drew010

120

ลองสิ่งนี้:

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

file_put_contents เอกสาร


4
ฉันลองสิ่งนี้ แต่มันรวมถึงตัวdata:image/png;base64,แบ่งไฟล์
Michael J. Calkins

2
@MichaelCalkins ทำลายให้ฉันเช่นกัน คำตอบของ drew010 ดูเหมือนจะเป็นทางออกเดียวที่ทำงานได้อย่างต่อเนื่อง
เดวิดจอห์นเวลส์

24
หากคุณรวมdata:image/png;base64,สตริงที่คุณกำลังส่งไปยังbase64_decodeไม่ถูกต้อง base64 คุณต้องส่งข้อมูลเท่านั้นซึ่งเป็นสิ่งที่คำตอบของ drew010 แสดงให้เห็น ไม่มีสิ่งใดหักด้วยคำตอบนี้ คุณไม่สามารถคัดลอกและวางโดยไม่เข้าใจและคาดหวังให้ "ทำงานได้"
Cypher

4
ไม่ทำงานสำหรับตัวอย่างที่มีให้ในคำถามซึ่งไม่ใช่เนื้อหาพื้นฐาน 64 และก่อนอื่นต้องแยกเป็นส่วน ๆ (ดูคำตอบที่ยอมรับ)
Benjamin Piette

บันทึกรูปภาพของฉันสำเร็จแล้ว แต่เมื่อฉันเขียน 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);ช่วยฉันมากขอบคุณ! เหตุใดฉันต้องแปลงพื้นที่เป็น "+" ก่อน
Sven

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ไหม
Bonswouar

1
@ Bonswouar ขอบคุณ เกี่ยวกับคำถามของคุณ: ในความคิดของฉันวิธีที่ดีที่สุดเพื่อให้แน่ใจว่าแอปพลิเคชันของคุณไม่มีปัญหาด้านประสิทธิภาพคือการวัดประสิทธิภาพในกรณีของคุณ (ขึ้นอยู่กับสภาพแวดล้อมขนาดไฟล์ที่คาดหวังและขนาดที่อนุญาตเป็นต้น) เราสามารถลองเล่นด้วยรหัสที่นี่และแสดงตัวเลขในคำตอบ แต่ความจริงก็คือสำหรับกรณีที่แน่นอนของคุณมันอาจนำมาซึ่งอันตรายมากกว่าผลบวก มันจะดีกว่าเสมอเพื่อให้แน่ใจในตัวคุณเอง (โดยเฉพาะถ้าเรากำลังพูดถึงส่วนที่สำคัญต่อประสิทธิภาพของแอพ)
Vladimir Posvistelik

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 framework, คำขอ 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

สร้าง 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).

รับส่วนขยายข้อมูลภาพและส่วน 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 มีฐานการรักษาที่ยุติธรรมแล้ว64 -> การแปลงไฟล์

ฉันใช้เพื่อให้เสร็จโดยใช้วิธีนี้:

$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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.