Nhận dữ liệu tệp mã hóa Base64 từ Biểu mẫu đầu vào


100

Tôi đã có một biểu mẫu HTML cơ bản mà từ đó tôi có thể lấy một chút thông tin mà tôi đang kiểm tra trong Firebug.

Vấn đề duy nhất của tôi là tôi đang cố gắng mã hóa base64 dữ liệu tệp trước khi nó được gửi đến máy chủ, nơi nó bắt buộc phải ở dạng đó để được lưu vào cơ sở dữ liệu.

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

Và trong Javascript + jQuery:

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

Tôi có một số hoạt động dựa trên javascript khả dụng: .getAsBinary (), .getAsText (), .getAsTextURL

Tuy nhiên, không có văn bản nào trong số này trả lại có thể sử dụng có thể được chèn vì chúng chứa các 'ký tự' không sử dụng được - Tôi không muốn xảy ra hiện tượng 'đăng lại' trong tệp của mình đã tải lên và tôi cần có nhiều biểu mẫu nhắm mục tiêu các đối tượng cụ thể nên điều quan trọng là tôi lấy tệp và sử dụng Javascript theo cách này.

Làm cách nào để tải tệp theo cách mà tôi có thể sử dụng một trong những bộ mã hóa Javascript base64 phổ biến rộng rãi !?

Cảm ơn

Cập nhật - Bắt đầu tiền thưởng tại đây, cần hỗ trợ nhiều trình duyệt !!!

Đây là nơi tôi đang ở:

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

Một số vấn đề với hỗ trợ nhiều trình duyệt:

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

Ngoài ra, IE không hỗ trợ:

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

Vì vậy, tôi phải thay thế bằng:

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

Đối với Hỗ trợ IE.

Tính năng này hoạt động trong Firefox, Chrome và Safari (nhưng không mã hóa tệp đúng cách hoặc ít nhất là sau khi được đăng, tệp không xuất hiện đúng cách)

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

Cũng thế,

file.readAsArrayBuffer() 

Có vẻ như chỉ được hỗ trợ trong HTML5?

Rất nhiều người đã đề xuất: http://www.webtoolkit.info/javascript-base64.html

Nhưng điều này chỉ trả về lỗi vi trên phương thức UTF_8 trước khi nó mã hóa base64? (hoặc một chuỗi trống)

var encoded = Base64.encode(file); 

Bạn đang tải gì lên? Dữ liệu văn bản hay nhị phân?
beatgammit

Dữ liệu nhị phân @tjamenson - bất kỳ thứ gì thực sự là 'tài liệu từ' 'pdf' 'hình ảnh', v.v. Tôi đã định gán tên tệp trong một biến khác nhưng tôi bắt đầu tự hỏi liệu tôi có mắc một lỗi nghiêm trọng nào đó trong hiểu biết về những gì có thể xảy ra với tải lên biểu mẫu và html - phương pháp này hoàn toàn không thể thực hiện được và không thể truyền dữ liệu tệp thông qua đăng nó dưới dạng chuỗi? Cũng không HTML5 mà tôi đọc có một số giải pháp -
jordan.baucke

Hấp dẫn. Tại sao bạn đang mã hóa base-64 giữa trình duyệt và máy chủ và cố gắng thực hiện điều này trong trình duyệt? Có vẻ như nếu bạn cố gắng bảo mật dữ liệu, SSL sẽ dễ dàng hơn nhiều vì nó mã hóa tất cả dữ liệu HTTP (bao gồm cả tệp) qua dây., Và bạn có thể phía máy chủ base-64, nếu cần cho cơ sở dữ liệu của bạn.
William Walseth

@William Tôi không cố bảo mật dữ liệu, chỉ đưa dữ liệu về đúng định dạng. Salesforce.com (nền tảng Apex) yêu cầu cơ sở dữ liệu được mã hóa base64 trước khi bản ghi được tạo trong cơ sở dữ liệu, chức năng của chúng để mã hóa dữ liệu tệp base64 thông qua một biểu mẫu được ghi chép rất kém (Tôi đã tìm ra cách thực hiện sau khi hỏi câu hỏi này). Dù sao, nó trông giống như base64 mã hóa dữ liệu tập tin nhị phân chỉ được hỗ trợ tự nhiên trong HTML5 hoặc Mozilla file API
jordan.baucke

1
OK, bây giờ tôi hiểu tại sao bạn cần cái này. Không có máy chủ trung gian + yêu cầu đám mây điên cuồng + không có giải pháp trình duyệt chéo = 1 mớ hỗn độn. Lấy làm tiếc.
William Walseth

Câu trả lời:


121

Nó hoàn toàn có thể xảy ra trong javascript phía trình duyệt.

Cách dễ dàng:

Phương thức readAsDataURL () có thể đã mã hóa nó thành base64 cho bạn. Có thể bạn sẽ cần loại bỏ những thứ bắt đầu (cho đến những thứ đầu tiên,), nhưng điều đó không có vấn đề gì. Điều này sẽ mất tất cả niềm vui mặc dù.

Con đường gian nan:

Nếu bạn muốn thử nó theo cách khó (hoặc nó không hiệu quả), hãy xem readAsArrayBuffer(). Điều này sẽ cung cấp cho bạn một Uint8Array và bạn có thể sử dụng phương thức được chỉ định. Điều này có lẽ chỉ hữu ích nếu bạn muốn làm rối với chính dữ liệu, chẳng hạn như thao tác dữ liệu hình ảnh hoặc thực hiện các phép thuật voodoo khác trước khi tải lên.

Có hai phương pháp:

  • Chuyển đổi thành chuỗi và sử dụng cài sẵn btoahoặc tương tự
    • Tôi chưa thử nghiệm tất cả các trường hợp, nhưng phù hợp với tôi- chỉ cần lấy mã char
  • Chuyển đổi trực tiếp từ Uint8Array sang base64

Gần đây tôi đã triển khai tar trong trình duyệt . Là một phần của quy trình đó, tôi đã thực hiện trực tiếp Uint8Array-> base64 của riêng mình. Tôi không nghĩ bạn sẽ cần điều đó, nhưng nó ở đây nếu bạn muốn xem qua; nó khá gọn gàng.

Những gì tôi làm bây giờ:

Mã để chuyển đổi thành chuỗi từ Uint8Array khá đơn giản (trong đó buf là 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;
}

Từ đó, chỉ cần làm:

var base64 = btoa(uint8ToString(yourUint8Array));

Base64 bây giờ sẽ là một chuỗi được mã hóa base64 và nó sẽ chỉ tải lên màu hồng đào. Hãy thử điều này nếu bạn muốn kiểm tra kỹ trước khi đẩy:

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

Thao tác này sẽ tải xuống dưới dạng tệp.

Thông tin khác:

Để lấy dữ liệu dưới dạng Uint8Array, hãy xem tài liệu MDN:


tuyệt vời - tôi nghĩ rằng readAsArrayBuffer()đầu ra trông giống như dữ liệu base64 chính xác , nhưng nó sẽ không xử lý do phần cầu xin của chuỗi - Tôi sẽ thử ngay bây giờ!
jordan.baucke

1
readAsArrayBuffer () dường như không tồn tại trong Chrome / Safari và tôi cho rằng sẽ có vấn đề trong các trình duyệt khác ~ có cách nào tương đương mà tôi có thể sử dụng trong các trình duyệt khác này không?
jordan.baucke

createObjectURL () <- ngoại hình này hứa hẹn, tôi sẽ cố gắng thực hiện điều đó, nhưng tôi chắc chắn rằng IE sẽ cần một bánh xe thứ 3
jordan.baucke

Có thể gán tên tệp trước khi thực thi giải pháp tải xuống của bạn không?
Ωmega

@ Ωmega - Không. Tất cả những việc này là tải xuống một luồng nhị phân. Không có cách nào (AFAIK) để chỉ định tên tệp. Một số trình duyệt đoán một phần mở rộng. Để lấy tên tệp, bạn sẽ phải tải lên rồi tải xuống lại.
beatgammit

37

Giải pháp của tôi đã được sử dụng readAsBinaryString()btoa()kết quả của nó.

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');
    };
}

3
Theo cách dễ dàng nhất, tại sao điều này không có nhiều phiếu bầu hơn?
sarink

14

Tôi đã sử dụng FileReader để hiển thị hình ảnh khi nhấp vào nút tải tệp lên mà không sử dụng bất kỳ yêu cầu Ajax nào. Sau đây là mã hy vọng nó có thể giúp một số người.

$(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

Sau khi tự mình đấu tranh với điều này, tôi đã triển khai FileReader cho các trình duyệt hỗ trợ nó (Chrome, Firefox và Safari 6 chưa được phát hành) và một tập lệnh PHP lặp lại dữ liệu tệp POSTed dưới dạng dữ liệu được mã hóa Base64 cho dữ liệu khác các trình duyệt.


0

Tôi bắt đầu nghĩ rằng việc sử dụng 'iframe' để tải lên kiểu Ajax có thể là lựa chọn tốt hơn nhiều cho tình huống của tôi cho đến khi HTML5 xuất hiện đầy đủ và tôi không phải hỗ trợ các trình duyệt cũ trong ứng dụng của mình!


Chỉ tò mò, tại sao bạn không chỉ cần lấy [ webtoolkit.info/javascript-base64.html#] , sau đó nhận xét input = Base64._utf8_encode(input);output = Base64._utf8_decode(output);? Bất kỳ vấn đề nào khác ngoài lỗi chuyển đổi utf-8?
shr

@shr Tôi không biết cách lấy dữ liệu tệp nhị phân để nhập vào các phương thức này trong mỗi trình duyệt? $('#inputid').files[0](không hoạt động trong IE7, theo như tôi có thể nói ). Nếu nó đã được dễ dàng? var output = Base64.encode($('#inputid').files[0])??
jordan.baucke

0

Lấy cảm hứng từ câu trả lời của @ 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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.