รับ Base64 เข้ารหัสไฟล์ข้อมูลจากแบบฟอร์มอินพุต


103

ฉันมีรูปแบบ HTML พื้นฐานซึ่งฉันสามารถดึงข้อมูลเล็กน้อยที่ฉันกำลังตรวจสอบใน Firebug

ปัญหาเดียวของฉันคือฉันกำลังพยายามเข้ารหัสข้อมูลไฟล์base64ก่อนที่จะส่งไปยังเซิร์ฟเวอร์ซึ่งต้องอยู่ในรูปแบบนั้นเพื่อบันทึกลงในฐานข้อมูล

<input type="file" id="fileupload" />

และใน Javascript + jQuery:

var file = $('#fileupload').attr("files")[0];

ฉันมีการดำเนินการบางอย่างที่ใช้ javascript ที่ใช้ได้: .getAsBinary (), .getAsText (), .getAsTextURL

อย่างไรก็ตามข้อความที่สามารถใช้งานได้เหล่านี้จะไม่สามารถแทรกกลับได้เนื่องจากมี'อักขระ' ที่ใช้ไม่ได้ - ฉันไม่ต้องการให้มี 'โพสต์แบ็ค' เกิดขึ้นในไฟล์ของฉันที่อัปโหลดและฉันจำเป็นต้องมีหลายรูปแบบที่กำหนดเป้าหมายไปที่ออบเจ็กต์เฉพาะดังนั้นฉันจึงสำคัญ รับไฟล์และใช้ Javascript ด้วยวิธีนี้

ฉันจะรับไฟล์ในลักษณะที่สามารถใช้ตัวเข้ารหัส Javascript base64 ตัวใดตัวหนึ่งที่มีให้ใช้งานอย่างแพร่หลาย!?

ขอบคุณ

อัปเดต - เริ่มต้นรางวัลที่นี่ต้องการการสนับสนุนข้ามเบราว์เซอร์ !!!

ที่นี่ฉันอยู่ที่:

<input type="file" id="fileuploadform" />

<script type="text/javascript">
var uploadformid = 'fileuploadform';
var uploadform = document.getElementById(uploadformid);


/* method to fetch and encode specific file here based on different browsers */

</script>

ปัญหาสองประการเกี่ยวกับการรองรับข้ามเบราว์เซอร์:

var file = $j(fileUpload.toString()).attr('files')[0];
fileBody = file.getAsDataURL(); // only would works in Firefox

นอกจากนี้ IE ไม่รองรับ:

var file = $j(fileUpload.toString()).attr('files')[0];

ดังนั้นฉันต้องแทนที่ด้วย:

var element = 'id';
var element = document.getElementById(id);

สำหรับการสนับสนุน IE

ใช้งานได้ใน Firefox, Chrome และ Safari (แต่ไม่ได้เข้ารหัสไฟล์อย่างถูกต้องหรืออย่างน้อยหลังจากโพสต์ไฟล์จะไม่ออกมาถูกต้อง)

var file = $j(fileUpload.toString()).attr('files')[0];
var encoded = Btoa(file);

นอกจากนี้

file.readAsArrayBuffer() 

ดูเหมือนว่าจะรองรับเฉพาะใน HTML5?

มีคนแนะนำมากมาย: http://www.webtoolkit.info/javascript-base64.html

แต่สิ่งนี้ส่งคืนเฉพาะข้อผิดพลาดบนเมธอด UTF_8 ก่อนที่จะเข้ารหัส base64? (หรือสตริงว่าง)

var encoded = Base64.encode(file); 

คุณกำลังอัปโหลดอะไร ข้อมูลข้อความหรือไบนารี?
beatgammit

@tjamenson ข้อมูลไบนารี - อะไรก็ได้ที่เป็น 'เอกสารคำ' 'pdf' 'รูปภาพ' ฯลฯ ฉันกำลังจะกำหนดชื่อไฟล์ในตัวแปรอื่น แต่ฉันเริ่มสงสัยว่าฉันมีข้อบกพร่องร้ายแรงหรือไม่ในความเข้าใจของสิ่งที่เป็นไปได้ อัพโหลดแบบฟอร์มและ html - วิธีนี้ใช้ไม่ได้ทั้งหมดและไม่สามารถส่งข้อมูลไฟล์ผ่านการโพสต์เป็นสตริงได้หรือไม่? นอกจากนี้ยังไม่มี HTML5 ซึ่งฉันกำลังอ่านมีวิธีแก้ปัญหาบางอย่าง -
jordan.baucke

น่าสนใจ. เหตุใดคุณจึงเข้ารหัส base-64 ระหว่างเบราว์เซอร์และเซิร์ฟเวอร์และพยายามทำสิ่งนี้ให้สำเร็จในเบราว์เซอร์ ดูเหมือนว่าหากคุณพยายามรักษาความปลอดภัยข้อมูล SSL จะง่ายกว่ามากเนื่องจากเข้ารหัสข้อมูล HTTP ทั้งหมด (รวมถึงไฟล์) ผ่านสายและคุณสามารถใช้ฝั่งเซิร์ฟเวอร์ฐาน 64 ได้หากจำเป็นสำหรับฐานข้อมูลของคุณ
William Walseth

@ วิลเลียมฉันไม่ได้พยายามรักษาความปลอดภัยข้อมูลเพียงแค่ทำให้ข้อมูลอยู่ในรูปแบบที่ถูกต้อง Salesforce.com (แพลตฟอร์ม Apex) กำหนดให้ฐานข้อมูลที่เข้ารหัส base64 ก่อนที่จะสร้างเรกคอร์ดในฐานข้อมูลฟังก์ชันการทำงานของพวกเขาในการเข้ารหัสข้อมูลไฟล์ base64 ผ่านแบบฟอร์มนั้นมีเอกสารที่ไม่ดีมาก (ฉันคิดวิธีการทำหลังจากถามคำถามนี้แล้ว) อย่างไรก็ตามดูเหมือนว่าข้อมูลไฟล์ไบนารีที่เข้ารหัส base64 ได้รับการสนับสนุนในHTML5หรือMozilla File API เท่านั้น
jordan.baucke

1
ตกลงตอนนี้ฉันเข้าใจแล้วว่าทำไมคุณถึงต้องการสิ่งนี้ ไม่มีเซิร์ฟเวอร์ระดับกลาง + ความต้องการระบบคลาวด์ที่บ้าคลั่ง + ไม่มีโซลูชันข้ามเบราว์เซอร์ = 1 ระเบียบ ขออภัย.
William Walseth

คำตอบ:


123

เป็นไปได้ทั้งหมดในจาวาสคริปต์ฝั่งเบราว์เซอร์

วิธีง่ายๆ:

readAsDataURL ()วิธีการเข้ารหัสแล้วอาจเป็น base64 สำหรับคุณ คุณอาจต้องตัดสิ่งที่เป็นจุดเริ่มต้นออกไป (ถึงอย่างแรก) แต่นั่นไม่ใช่เรื่องใหญ่ สิ่งนี้จะนำความสนุกทั้งหมดออกไป

วิธีที่ยาก:

หากคุณต้องการลองวิธีที่ยาก (หรือไม่ได้ผล) ให้ดูที่ readAsArrayBuffer()ดูที่ สิ่งนี้จะให้ Uint8Array แก่คุณและคุณสามารถใช้วิธีการที่ระบุได้ สิ่งนี้อาจมีประโยชน์ก็ต่อเมื่อคุณต้องการยุ่งกับข้อมูลเช่นการจัดการข้อมูลรูปภาพหรือทำเวทมนตร์วูดูอื่น ๆ ก่อนที่คุณจะอัปโหลด

มีสองวิธี:

  • แปลงเป็นสตริงและใช้ในตัว btoaหรือคล้ายกัน
    • ฉันไม่ได้ทดสอบทุกกรณี แต่ใช้ได้กับฉัน - เพียงแค่รับรหัสถ่าน
  • แปลงโดยตรงจาก Uint8Array เป็น base64

ฉันเพิ่งดำเนินการน้ำมันดินในเบราว์เซอร์ ในขั้นตอนนั้นฉันได้สร้าง Uint8Array-> base64 โดยตรงของตัวเอง ฉันไม่คิดว่าคุณจะต้องการสิ่งนั้น แต่ที่นี่ถ้าคุณต้องการดู มันค่อนข้างเรียบร้อย

ตอนนี้ฉันทำอะไร:

รหัสสำหรับการแปลงเป็นสตริงจาก Uint8Array นั้นค่อนข้างง่าย (โดยที่ buf คือ Uint8Array):

function uint8ToString(buf) {
    var i, length, out = '';
    for (i = 0, length = buf.length; i < length; i += 1) {
        out += String.fromCharCode(buf[i]);
    }
    return out;
}

จากนั้นให้ทำ:

var base64 = btoa(uint8ToString(yourUint8Array));

ตอนนี้ Base64 จะเป็นสตริงที่เข้ารหัส base64 และควรอัปโหลดเพียงพีชชี่ ลองทำเช่นนี้หากคุณต้องการตรวจสอบอีกครั้งก่อนกด:

window.open("data:application/octet-stream;base64," + base64);

เพื่อดาวน์โหลดเป็นไฟล์

ข้อมูลอื่น ๆ :

ในการรับข้อมูลเป็น Uint8Array ให้ดูที่เอกสาร MDN:


เยี่ยมมาก - ฉันคิดว่าreadAsArrayBuffer()ผลลัพธ์ที่ได้ดูเหมือนว่าข้อมูลbase64 ที่ถูกต้องแต่มันจะไม่ประมวลผลเนื่องจากเป็นส่วนที่ขอทาน - ฉันจะให้มันถ่ายตอนนี้!
jordan.baucke

1
readAsArrayBuffer () ดูเหมือนจะไม่มีใน Chrome / Safari และฉันคิดว่าจะมีปัญหาในเบราว์เซอร์อื่น ~ มีสิ่งที่เทียบเท่าฉันสามารถใช้ในเบราว์เซอร์อื่น ๆ เหล่านี้ได้หรือไม่
jordan.baucke

createObjectURL () <- ดูเหมือนว่าฉันจะพยายามใช้มัน แต่ฉันแน่ใจว่า IE จะต้องใช้วงล้อที่ 3
jordan.baucke

เป็นไปได้ไหมที่จะกำหนดชื่อไฟล์ก่อนดำเนินการดาวน์โหลดของคุณ?
Ωmega

@ Ωmega - ไม่ทั้งหมดนี้คือดาวน์โหลดสตรีมไบนารี ไม่มีทาง (AFAIK) ในการระบุชื่อไฟล์ เบราว์เซอร์บางตัวคาดเดาส่วนขยายได้ หากต้องการรับชื่อไฟล์คุณจะต้องอัปโหลดแล้วดาวน์โหลดอีกครั้ง
beatgammit

41

วิธีแก้ปัญหาของฉันคือการใช้งานreadAsBinaryString()และbtoa()ผลลัพธ์ของมัน

uploadFileToServer(event) {
    var file = event.srcElement.files[0];
    console.log(file);
    var reader = new FileReader();
    reader.readAsBinaryString(file);

    reader.onload = function() {
        console.log(btoa(reader.result));
    };
    reader.onerror = function() {
        console.log('there are some problems');
    };
}

4
วิธีที่ง่ายที่สุดทำไมถึงไม่มีคะแนนโหวตมากกว่านี้
sarink

14

ฉันใช้ FileReader เพื่อแสดงภาพเมื่อคลิกปุ่มอัปโหลดไฟล์โดยไม่ใช้คำขอ Ajax ใด ๆ ต่อไปนี้เป็นรหัสหวังว่ามันอาจช่วยได้บ้าง

$(document).ready(function($) {
    $.extend( true, jQuery.fn, {        
        imagePreview: function( options ){          
            var defaults = {};
            if( options ){
                $.extend( true, defaults, options );
            }
            $.each( this, function(){
                var $this = $( this );              
                $this.bind( 'change', function( evt ){

                    var files = evt.target.files; // FileList object
                    // Loop through the FileList and render image files as thumbnails.
                    for (var i = 0, f; f = files[i]; i++) {
                        // Only process image files.
                        if (!f.type.match('image.*')) {
                        continue;
                        }
                        var reader = new FileReader();
                        // Closure to capture the file information.
                        reader.onload = (function(theFile) {
                            return function(e) {
                                // Render thumbnail.
                                    $('#imageURL').attr('src',e.target.result);                         
                            };
                        })(f);
                        // Read in the image file as a data URL.
                        reader.readAsDataURL(f);
                    }

                });
            });
        }   
    });
    $( '#fileinput' ).imagePreview();
});

1

หลังจากต่อสู้กับสิ่งนี้ด้วยตัวเองฉันได้มาใช้ FileReader สำหรับเบราว์เซอร์ที่รองรับ (Chrome, Firefox และ Safari 6 ที่ยังไม่เปิดตัว) และสคริปต์ PHP ที่สะท้อนกลับข้อมูลไฟล์ที่โพสต์เป็นข้อมูลที่เข้ารหัส Base64 สำหรับอีกอัน เบราว์เซอร์


1

แรงบันดาลใจจากคำตอบของ @ Josef:

const fileToBase64 = async (file) =>
  new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = () => resolve(reader.result)
    reader.onerror = (e) => reject(e)
  })

const file = event.srcElement.files[0];
const imageStr = await fileToBase64(file)

-1

ฉันเริ่มคิดว่าการใช้ 'iframe' สำหรับการอัปโหลดสไตล์ Ajax อาจเป็นทางเลือกที่ดีกว่ามากสำหรับสถานการณ์ของฉันจนกว่าHTML5จะมาเต็มวงและฉันไม่ต้องรองรับเบราว์เซอร์เดิมในแอปของฉัน!


แค่อยากรู้ทำไมคุณไม่ลองใช้ [ webtoolkit.info/javascript-base64.html#]แล้วจึงแสดงความคิดเห็นinput = Base64._utf8_encode(input);และoutput = Base64._utf8_decode(output);? มีปัญหาอื่นนอกเหนือจากข้อผิดพลาดในการแปลง utf-8 หรือไม่?
shr

ฉันไม่รู้ว่าจะคว้าข้อมูลไฟล์ไบนารีเพื่อป้อนข้อมูลในวิธีการเหล่านี้ในแต่ละเบราว์เซอร์ได้อย่างไร? $('#inputid').files[0](ไม่ทำงานใน IE7 เท่าที่ฉันสามารถบอกได้ ) ถ้ามันง่ายขนาดนั้น? var output = Base64.encode($('#inputid').files[0])??
jordan.baucke
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.