2015-05-02 11 views
5

Tôi muốn cho phép người dùng kéo hình ảnh từ màn hình của họ lên cửa sổ trình duyệt rồi tải những hình ảnh đó lên máy chủ. Tôi muốn tải lên từng tệp một lần, ngay cả khi nó bị bỏ trên cửa sổ nhiều lần. Vì lý do bảo mật, thông tin từ đối tượng Tệp có thể truy cập JavaScript bị giới hạn. Theo msdn.microsoft.com, chỉ có các tính chất sau đây có thể được đọc:Phát hiện xem người dùng có thả cùng một tệp hai lần trên cửa sổ trình duyệt không

  • name
  • lastModifiedDate

(Safari cũng cho thấy nhiều sizetype).

Người dùng có thể thả hai hình ảnh có cùng tên và ngày sửa đổi lần cuối từ các thư mục khác nhau vào cửa sổ trình duyệt. Có một cơ hội rất nhỏ nhưng hữu hạn mà hai hình ảnh này trong thực tế khác nhau.

Tôi đã tạo tập lệnh đọc trong dataURL thô của mỗi tệp hình ảnh và so sánh tập lệnh đó với các tệp đã bị xóa trước đó trên cửa sổ. Một lợi thế của việc này là nó có thể phát hiện các tệp giống hệt nhau với các tên khác nhau.

Công trình này, nhưng có vẻ như quá mức. Nó cũng đòi hỏi một lượng lớn dữ liệu được lưu trữ. Tôi có thể cải thiện điều này (và thêm vào overkill) bằng cách tạo một hash của dataURL và lưu trữ thay vào đó.

Tôi hy vọng rằng có thể có một cách thanh lịch hơn để đạt được mục tiêu của mình. Những gì bạn có thể đề nghị?

<!DOCTYPE html> 
<html> 
<head> 
    <title>Detect duplicate drops</title> 
    <style> 
html, body { 
width: 100%; 
height: 100%; 
margin: 0; 
background: #000; 
} 
    </style> 
    <script> 
var body 
var imageData = [] 


document.addEventListener('DOMContentLoaded', function ready() { 
    body = document.getElementsByTagName("body")[0] 
    body.addEventListener("dragover", swallowEvent, false) 
    body.addEventListener("drop", treatDrop, false) 
}, false) 


function swallowEvent(event) { 
    // Prevent browser from loading the dropped image in an empty page 
    event.preventDefault() 
    event.stopPropagation() 
} 


function treatDrop(event) { 
    swallowEvent(event) 

    for (var ii=0, file; file = event.dataTransfer.files[ii]; ii++) { 
    importImage(file) 
    } 
} 


function importImage(file) { 
    var reader = new FileReader() 

    reader.onload = function fileImported(event) { 
     var dataURL = event.target.result 
     var index = imageData.indexOf(dataURL) 
     var img, message 

     if (index < 0) { 
      index = imageData.length 
      console.log(dataURL) 
      imageData.push(dataURL, file.name) 
      message = "Image "+file.name+" imported" 
     } else { 
      message = "Image "+file.name+" imported as "+imageData[index+1] 
     } 

     img = document.createElement("img") 
     img.src = imageData[index] // copy or reference? 
     body.appendChild(img) 

     console.log(message) 
    } 

    reader.readAsDataURL(file) 
} 
    </script> 
</head> 
<body> 
</body> 
</html> 
+0

Tôi khuyên bạn nên cho phép người dùng tải lên hình ảnh một cách bừa bãi (với một số JS để đảm bảo rằng chúng thực sự là hình ảnh). Sau đó, phía máy chủ, bạn sẽ thực hiện các hoạt động chuyên sâu của CPU và so sánh các tệp để xem chúng có giống nhau hay không ... nếu chúng là, từ chối một trong các hình ảnh và thông báo cho người dùng. Nếu không, hãy băm tên và lưu trữ chúng – Literphor

+0

Cảm ơn đề xuất của bạn, @Literphor. Tuy nhiên, trong trường hợp cụ thể này, điều quan trọng là chỉ nên có một bản sao phía máy khách của mỗi hình ảnh. –

+0

'file.size' được hỗ trợ tốt, vì vậy bạn có thể giảm tỷ lệ cược mà không cần xử lý dữ liệu tệp. – dandavis

Trả lời

0

Dưới đây là một gợi ý (mà tôi đã không nhìn thấy được đề cập trong câu hỏi của bạn):

Tạo một Blob URL cho mỗi file -object trong FileList -object phải được lưu trữ trong trình duyệt URL Store, lưu chuỗi URL của họ.

Sau đó, bạn vượt qua URL dây đến một webworker (thread riêng biệt) trong đó sử dụng các FileReader để đọc mỗi tập tin (truy cập thông qua chuỗi URL Blob) trong chunked phần, tái sử dụng một đệm kích thước cố định (gần giống như một bộ đệm tròn), để tính toán băm của tệp (có các băm đơn giản/nhanh có thể mang theo như crc32, thường có thể được kết hợp đơn giản với một tổng kiểm tra dọc và ngang trong cùng một vòng lặp (cũng có thể mang theo các khối)) .
Bạn có thể tăng tốc quá trình bằng cách đọc các giá trị 32 bit (chưa ký) thay vì giá trị 8 bit bằng cách sử dụng 'bufferview' thích hợp (nhanh gấp 4 lần). Hệ thống endianness là không quan trọng, không lãng phí tài nguyên về điều này!

Sau khi hoàn thành webworker, sau đó trả lại hàm băm của tệp cho ứng dụng/luồng chính mà sau đó chỉ cần thực hiện so sánh ma trận của bạn là [[fname, fsize, blobUrl, fhash] /* , etc /*].

Pro
Bộ đệm cố định tái sử dụng mang lại đáng kể xuống sử dụng bộ nhớ của bạn (bất kỳ mức bạn chỉ định), các WebWorker sẽ trả về hiệu suất bằng cách sử dụng các chủ đề phụ (mà không chặn chủ đề trình duyệt chính của bạn) .

Côn
Bạn sẽ vẫn cần serverside mùa thu lại cho các trình duyệt với Javascript bị vô hiệu (bạn có thể thêm một lĩnh vực tiềm ẩn mẫu và thiết lập giá trị của nó bằng javascript như phương tiện của một tấm séc được bật javascript, như tải phía máy chủ thấp hơn). Tuy nhiên .. thậm chí sau đó .. bạn vẫn cần phải dự phòng phía máy chủ để bảo vệ chống lại đầu vào độc hại.

Tính hữu ích
Vì vậy, không có lợi ích ròng? Vâng .. nếu cơ hội là hợp lý mà người dùng có thể tải lên các tập tin trùng lặp (hoặc chỉ sử dụng chúng trong một ứng dụng dựa trên web) hơn bạn đã lưu trên băng thông eo chỉ để thực hiện kiểm tra. Đó là một chiến thắng khá (sinh thái/tài chính) trong cuốn sách của tôi.


tắm
Hashes dễ bị va chạm, thời gian. Để giảm nguy cơ va chạm (thực tế) bạn muốn chọn một băm algo nâng cao hơn (hầu hết là dễ dàng mang theo trong chế độ chunked). Giao dịch rõ ràng cho các băm nâng cao hơn là kích thước mã lớn hơn và tốc độ thấp hơn (sử dụng CPU cao hơn).

Các vấn đề liên quan