จำกัด รูปแบบไฟล์เมื่อใช้ <input type =“ file”> หรือไม่


667

ฉันต้องการ จำกัด ประเภทของไฟล์ที่สามารถเลือกได้จากตัวเลือกไฟล์ดั้งเดิมของระบบปฏิบัติการเมื่อผู้ใช้คลิกปุ่มเรียกดูใน<input type="file">องค์ประกอบใน HTML ผมมีความรู้สึกว่ามันเป็นไปไม่ได้ แต่ผมอยากจะทราบว่ามีเป็นวิธีการแก้ปัญหา ฉันต้องการเก็บเฉพาะ HTML และ JavaScript กรุณาอย่าแฟลช


1
เป็นไปได้อย่างง่ายดายกับ PHP แต่ฉันไม่รู้ว่าคุณสามารถใช้มันได้หรือไม่ดังนั้นฉันจะไม่โพสต์โค้ด
Latox

2
ฉันทำได้ แต่ฉันมีวิธีแก้ปัญหาการทำงานกับ JavaScript - มันลบความน่ารำคาญของการอัปโหลดไฟล์จากนั้นรับ "ไฟล์ผิด!" ความผิดพลาด
Bojangles

ดูคำถามล่าสุดเพิ่มเติมได้ที่: stackoverflow.com/questions/181214/…
Christophe Roussy

สิ่งหนึ่งที่ควรทราบคือแม้ว่าจะไม่ดีสำหรับการตรวจสอบความถูกต้องการยอมรับจะ จำกัด ไฟล์ที่มองเห็นให้กับไฟล์ที่ยอมรับได้ในขณะที่ผู้ใช้เรียกดู (อย่างน้อยในเบราว์เซอร์บางตัว ... ) ดังนั้นนี่เป็นคุณสมบัติการยศาสตร์ของ UI มากกว่าการตรวจสอบความถูกต้อง
Christophe Roussy

คำตอบ:


1119

พูดอย่างเคร่งครัดคำตอบคือไม่มี นักพัฒนาไม่สามารถป้องกันผู้ใช้จากการอัปโหลดไฟล์ประเภทหรือส่วนขยายใด ๆ

แต่ถึงกระนั้นคุณสมบัติการยอมรับของ<input type = "file">สามารถช่วยให้ตัวกรองในกล่องโต้ตอบเลือกไฟล์ของระบบปฏิบัติการ ตัวอย่างเช่น,

<!-- (IE 10+, Edge (EdgeHTML), Edge (Chromium), Chrome, Firefox 42+) -->
<input type="file" accept=".xls,.xlsx" />

ควรมีวิธีในการกรองไฟล์อื่นที่ไม่ใช่. xls หรือ. xlsx ถึงแม้ว่าหน้าMDNสำหรับinputองค์ประกอบจะกล่าวว่ามันสนับสนุนสิ่งนี้ แต่ก็ไม่ได้ผลสำหรับฉันใน Firefox จนถึงรุ่น 42 ซึ่งสามารถใช้งานได้ใน IE 10+, Edge และ Chrome

ดังนั้นสำหรับการสนับสนุน Firefox ที่มีอายุมากกว่า 42 พร้อมกับ IE 10+, Edge, Chrome และ Opera ฉันคิดว่าเป็นการดีกว่าที่จะใช้รายการ MIME-types ที่คั่นด้วยเครื่องหมายจุลภาค:

<!-- (IE 10+, Edge (EdgeHTML), Edge (Chromium), Chrome, Firefox) -->
<input type="file"
 accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel" /> 

[ ลักษณะการทำงานEdge (EdgeHTML): ดรอปดาวน์ตัวกรองประเภทไฟล์จะแสดงประเภทไฟล์ที่กล่าวถึงที่นี่ แต่ไม่ใช่ค่าเริ่มต้นในดรอปดาวน์ ตัวกรองเริ่มต้นคือAll files (*)]

นอกจากนี้คุณยังสามารถใช้เครื่องหมายดอกจันในประเภท MIME ตัวอย่างเช่น:

<input type="file" accept="image/*" /> <!-- all image types --> 
<input type="file" accept="audio/*" /> <!-- all audio types --> 
<input type="file" accept="video/*" /> <!-- all video types --> 

W3C แนะนำให้ผู้เขียนระบุทั้งประเภท MIME และส่วนขยายที่เกี่ยวข้องในacceptแอตทริบิวต์ ดังนั้นวิธีที่ดีที่สุดคือ:

<!-- Right approach: Use both file extensions and corresponding MIME-types. -->
<!-- (IE 10+, Edge (EdgeHTML), Edge (Chromium), Chrome, Firefox) -->
<input type="file"
 accept=".xls,.xlsx, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel" /> 

JSFiddle ของเดียวกัน: ที่นี่

การอ้างอิง: รายการประเภท MIME

สำคัญ:การใช้แอacceptททริบิวให้วิธีการกรองในไฟล์ประเภทที่น่าสนใจเท่านั้น เบราว์เซอร์ยังอนุญาตให้ผู้ใช้เลือกไฟล์ประเภทใดก็ได้ ควรทำการตรวจสอบเพิ่มเติม (ฝั่งไคลเอ็นต์) (โดยใช้ JavaScript วิธีนี้จะเป็นอย่างนั้น ) และประเภทไฟล์ที่แน่นอนต้องตรวจสอบบนเซิร์ฟเวอร์โดยใช้การรวมกันของประเภท MIME โดยใช้ทั้งนามสกุลไฟล์และลายเซ็นไบนารี ( ASP) .NET , PHP , Ruby , Java ) คุณอาจต้องการอ้างถึงตารางเหล่านี้ สำหรับประเภทไฟล์และหมายเลขเวทย์มนตร์เพื่อทำการตรวจสอบฝั่งเซิร์ฟเวอร์ที่มีประสิทธิภาพยิ่งขึ้น

ต่อไปนี้เป็นสามการ อ่านที่ดี สำหรับการอัปโหลดไฟล์และความปลอดภัย

แก้ไข: บางทีการตรวจสอบประเภทไฟล์โดยใช้ลายเซ็นไบนารีของมันยังสามารถทำได้ในฝั่งไคลเอ็นต์โดยใช้ JavaScript (แทนที่จะเพียงแค่ดูที่ส่วนขยาย) โดยใช้ HTML5 File API แต่ยังคงต้องตรวจสอบไฟล์บนเซิร์ฟเวอร์เนื่องจากผู้ใช้ที่ประสงค์ร้าย จะยังคงสามารถอัปโหลดไฟล์ได้โดยทำคำขอ HTTP ที่กำหนดเอง


2
@Sandesire ฉันไม่คิดว่าคุณสามารถ จำกัด ขนาดไฟล์เป็น HTML ได้ เป็นไปได้โดยใช้ JavaScript ตามที่คุณแนะนำ
Sachin Joseph

1
จากประสบการณ์ส่วนตัวของฉันนี่ดูเหมือนคำตอบที่ดีประเภท mime เพียงอย่างเดียวจะไม่สามารถใช้ได้กับเบราว์เซอร์ทั้งหมด
Christophe Roussy

1
อนึ่งacceptยังไม่ทำงานในขอบ: stackoverflow.com/questions/31875617/... รายละเอียดเพิ่มเติมได้ที่นี่: wpdev.uservoice.com/forums/257854-microsoft-edge-developer/ …
SharpC

1
exclude="exe"ฉันหวังว่าเรามีทางเลือกที่จะไม่รวมไฟล์เช่นกันยกตัวอย่างเช่น ¯_ (ツ) _ / ¯
Sagiv bg

1
เพื่อชี้แจงลักษณะการทำงานของ Edge เพิ่มเติม (ตามการทดสอบของฉัน) มันจะเพิ่มตัวกรองที่แตกต่างกันตามสิ่งที่คุณระบุ แต่ a) มันไม่ได้รวมอยู่ด้วยดังนั้นมันจะแสดงรายการส่วนขยายแต่ละรายการเป็นตัวเลือกแยกต่างหากและ b) ส่วนขยายการสร้างเช่น. html และ c) ตามที่ระบุไว้แล้วมันจะเลือกล่วงหน้า (*) เสมอ ซึ่งทำให้เป็นระเบียบใหญ่และไร้ประโยชน์ในกรณีส่วนใหญ่ ฉันโหวตให้กับลิงค์ uservoice เราหวังว่าพวกเขาจะฟังไม่ช้าก็เร็ว
Arie

198

มีแอตทริบิวต์ accept สำหรับแท็กอินพุต อย่างไรก็ตามมันไม่น่าเชื่อถือ แต่อย่างใด เบราว์เซอร์ส่วนใหญ่ถือว่าเป็น "คำแนะนำ" ซึ่งหมายความว่าผู้ใช้จะขึ้นอยู่กับตัวจัดการไฟล์ด้วยมีตัวเลือกล่วงหน้าที่แสดงประเภทที่ต้องการเท่านั้น พวกเขายังคงสามารถเลือก "ไฟล์ทั้งหมด" และอัปโหลดไฟล์ใดก็ได้ที่พวกเขาต้องการ

ตัวอย่างเช่น:

<form>
    <input type="file" name="pic" id="pic" accept="image/gif, image/jpeg" />
</form>

อ่านเพิ่มเติมในสเป็ค HTML5

โปรดทราบว่ามันจะใช้เป็น "ช่วย" สำหรับผู้ใช้ในการค้นหาไฟล์ที่ถูกต้องเท่านั้น ผู้ใช้ทุกคนสามารถส่งคำขอใด ๆ ที่เขา / เธอต้องการไปยังเซิร์ฟเวอร์ของคุณ คุณต้องตรวจสอบทุกอย่างที่ฝั่งเซิร์ฟเวอร์เสมอ

ดังนั้นคำตอบคือไม่มีคุณไม่สามารถ จำกัดแต่คุณสามารถตั้งค่าการเลือกก่อน แต่คุณไม่สามารถพึ่งพาได้

หรือนอกจากนี้คุณสามารถทำสิ่งที่คล้ายกันได้โดยตรวจสอบชื่อไฟล์ (ค่าของฟิลด์อินพุต) ด้วย JavaScript แต่สิ่งนี้ไร้สาระเพราะไม่มีการป้องกันและไม่ทำให้การเลือกของผู้ใช้ง่ายขึ้น มันอาจหลอกให้เว็บมาสเตอร์คิดว่าเขา / เธอได้รับการคุ้มครองและเปิดช่องโหว่ความปลอดภัย มันอาจเป็นความเจ็บปวดใน ass สำหรับผู้ใช้ที่มีนามสกุลไฟล์สำรอง (เช่น jpeg แทน jpg), ตัวพิมพ์ใหญ่หรือไม่มีนามสกุลไฟล์ใด ๆ (ตามปกติบนระบบ Linux)


3
สำหรับข้อมูลเพิ่มเติมดูstackoverflow.com/questions/181214/…
Martin Meeser

1
แม้ว่ามันจะเป็นความจริงที่เป็นไปไม่ได้ที่จะป้องกันไม่ให้ผู้ใช้เลือกไฟล์ชนิดใดก็ได้ในที่สุดวันนี้คุณสามารถใช้ประโยชน์จาก HTML5 File API และทำงานกับไฟล์ที่เลือกเพื่ออัปโหลดก่อนที่มันจะถูกอัพโหลดจริงไปยังเซิร์ฟเวอร์ ประเภทขนาดและอื่น ๆ ให้มันลอง. มันใช้งานง่ายมาก แต่ทรงพลังและมีประโยชน์มาก
TheCuBeMan

96

คุณสามารถใช้changeเหตุการณ์เพื่อตรวจสอบสิ่งที่ผู้ใช้เลือกและแจ้งให้พวกเขาทราบ ณ จุดนั้นว่าไฟล์ไม่เป็นที่ยอมรับ ไม่ จำกัด รายการไฟล์จริงที่แสดง แต่มันใกล้เคียงที่สุดที่คุณสามารถทำได้ฝั่งไคลเอ็นต์นอกเหนือจากacceptแอตทริบิวต์ที่ได้รับการสนับสนุนไม่ดี

var file = document.getElementById('someId');

file.onchange = function(e) {
  var ext = this.value.match(/\.([^\.]+)$/)[1];
  switch (ext) {
    case 'jpg':
    case 'bmp':
    case 'png':
    case 'tif':
      alert('Allowed');
      break;
    default:
      alert('Not allowed');
      this.value = '';
  }
};
<input type="file" id="someId" />

JSFiddle


11
@ โจมันเป็นตัวอย่าง ... มันสามารถขยายไปยังส่วนขยายใด ๆ ที่คุณต้องการอนุญาต
Gabriele Petrioli

ใช่คุณสามารถ แต่คุณไม่ได้! และมีคนคัดลอกมาแล้ว! และไฟล์ประเภท mime ที่ถูกต้อง แต่ไม่มีนามสกุลอะไร
Surrican

49
@ โจ .. อืม .. ฉันพยายามกำหนดทิศทางและลอจิกเสียง โซลูชันที่ไม่ได้ใช้งานอย่างสมบูรณ์สำหรับทุกกรณี ฉันเชื่อว่าผู้ชมจะใช้สามัญสำนึกเมื่อคัดลอก / วางรหัสจากเว็บ;)
Gabriele Petrioli

7
วิธีการเกี่ยวกับ "Some.File.jpg" บางทีบรรทัด regex ต้องการอ่าน: var ext = this.value.match (/ \. ([^.] +) $ /) [1];
Jon Kloske

ปัญหาของวิธีนี้คือบางสิ่งอาจยังคงเป็น jpeg ในทางเทคนิคแม้ว่าจะไม่ได้ลงท้ายด้วยส่วนขยายนั้น ส่วนขยาย! == ประเภท mime
Matt Fletcher

46

ใช่คุณถูก. มันเป็นไปไม่ได้กับ HTML ผู้ใช้จะสามารถเลือกไฟล์ใดก็ได้ที่เขา / เธอต้องการ

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

สิ่งที่ต้องการ:

function beforeSubmit()
{
    var fname = document.getElementById("ifile").value;
    // check if fname has the desired extension
    if (fname hasDesiredExtension) {
        return true;
    } else {
        return false;
    }
}

รหัส HTML:

<form method="post" onsubmit="return beforeSubmit();">
    <input type="file" id="ifile" name="ifile"/>
</form>

3
มีแอตทริบิวต์ html ที่ถูกต้องครบถ้วนเพื่อให้เป็นไปได้ เบราว์เซอร์ไม่ได้รับการยอมรับ แต่เป็นปัญหามาตรฐาน เช่นเดียวกับสิ่งใดก็ตามที่จัดการฝั่งไคลเอ็นต์ในมาร์กอัปที่ไม่มีการป้องกันไม่สามารถ จำกัด สิ่งที่จาวาสคริปต์ได้ไม่มีวิธีแก้ปัญหา
Surrican

2
จุดที่ดีมาก ฉันจะเพิ่มตัวตรวจสอบ PHP ตัวที่สองในกรณี ต้องระวังตัวมากเกินไป!
Bojangles

2
ก็ไม่เป็นอันตรายหากฉันใช้สคริปต์ตรวจสอบ PHP ด้วยดังนั้นฉันจะใช้ทั้งสองอย่าง
Bojangles

17
@Joe: หยุดพูดว่าคำตอบของฉัน sucks! :-) อย่างไรก็ตามมันไม่ได้เป็นโซลูชั่นที่สมบูรณ์แบบ ดังที่ฉันได้กล่าวไว้ในตอนต้น: "เป็นไปไม่ได้" ที่จะทำในสิ่งที่ OP ต้องการ แต่คุณสามารถมีบางระดับของความช่วยเหลือสำหรับผู้ใช้ถ้าคุณจะให้เขา / เธอเลือกไฟล์ที่มีนามสกุลบางอย่าง จริงการตรวจสอบประเภทของไฟล์ต้องทำด้านเซิร์ฟเวอร์
Pablo Santa Cruz

11
@JoeHopfgartner: เพื่อนคุณมีความเมตตามากเกินไปสำหรับ Pablo ที่นี่ การตรวจสอบความถูกต้องของลูกค้านั้นทำได้ในหลาย ๆ ที่และถึงแม้ว่าจะไม่สามารถป้องกันได้ (ควรมี [b] เสมอ [/ b] รวมถึงการตรวจสอบความถูกต้องของเซิร์ฟเวอร์ด้วย) มันสามารถบันทึกผู้ใช้ได้ค่อนข้างบางครั้ง ในขณะที่สคริปต์ของ Pablo นั้นไม่สมบูรณ์แบบมันมีจุดประสงค์เพียงเพื่อเป็นตัวอย่างของวิธีแก้ไขปัญหานี้ ... บางทีคุณควรส่งอีเมลถึงพวกนักเทคโนโลยีที่ Microsoft และขอให้ลบการตรวจสอบไคลเอนต์ออกจากเครื่องมือตรวจสอบ ASP.NET ของพวกเขาตั้งแต่ มันเป็นขยะธรรมดาสำหรับคุณ ...
นาธาน

18

ในทางเทคนิคคุณสามารถระบุacceptคุณสมบัติ (ทางเลือกในhtml5 ) ในinputองค์ประกอบ แต่ไม่รองรับอย่างถูกต้อง


การสนับสนุนเบราว์เซอร์ W3Schools ล้มเหลว! มันเป็นความอัปยศจริงๆ นอกจากนี้ยังเป็นปัญหาด้านความปลอดภัย - ผู้คนสามารถแฮกรหัสฝั่งไคลเอ็นต์ที่ผ่านมาและอัปโหลดสิ่งที่พวกเขาต้องการ
Bojangles

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

10

ใช้inputแท็กที่มีacceptคุณสมบัติ

<input type="file" name="my-image" id="image" accept="image/gif, image/jpeg, image/png" />

คลิกที่นี่สำหรับตารางความเข้ากันได้ของเบราว์เซอร์ล่าสุด

การสาธิตสดที่นี่

เพื่อเลือกไฟล์ภาพเท่านั้นคุณสามารถใช้สิ่งนี้ accept="image/*"

<input type="file" name="my-image" id="image" accept="image/*" />

การสาธิตสดที่นี่

จะแสดงเฉพาะ gif, jpg และ png เท่านั้นการจับหน้าจอจาก Chrome เวอร์ชัน 44 จะแสดงเฉพาะ gif, jpg และ png เท่านั้นการจับหน้าจอจาก Chrome เวอร์ชัน 44


ขอบคุณ! ใน Chrome บน Win10 ถ้าฉันใช้accept="image/*"มันจะบอกว่า "Image Files" แทนที่จะเป็น "Custom Files" ในเครื่องมือเลือกไฟล์ซึ่งเหมาะสำหรับผู้ใช้ปลายทาง
ตุ๊กตา

แต่ผู้ใช้สามารถเปลี่ยนและอัปโหลดไฟล์นามสกุลอื่น ๆ ได้
Prashant Prajapati

@PrashantPrajapati ใช่นั่นเป็นวิธีที่สร้างเบราว์เซอร์ควรมีการตรวจสอบความถูกต้องที่สอดคล้องกันในเซิร์ฟเวอร์ฟังก์ชั่นเบราว์เซอร์เป็นเพียงเพื่อประสบการณ์การใช้งานที่ดีขึ้น
kiranvj

9

ฉันรู้ว่ามันช้าไปหน่อย

function Validatebodypanelbumper(theForm)
{
   var regexp;
   var extension =     theForm.FileUpload.value.substr(theForm.FileUpload1.value.lastIndexOf('.'));
   if ((extension.toLowerCase() != ".gif") &&
       (extension.toLowerCase() != ".jpg") &&
       (extension != ""))
   {
      alert("The \"FileUpload\" field contains an unapproved filename.");
      theForm.FileUpload1.focus();
      return false;
   }
   return true;
}

5

คุณสามารถทำได้จริงด้วย javascript แต่จำไว้ว่า js คือฝั่งไคลเอ็นต์ดังนั้นคุณจะต้อง "เตือนผู้ใช้" ว่าไฟล์ประเภทใดที่พวกเขาสามารถอัปโหลดได้ถ้าคุณต้องการหลีกเลี่ยงข้อ จำกัด หรือ จำกัด ตามที่คุณกล่าวไว้ ทำฝั่งเซิร์ฟเวอร์

ดูTut พื้นฐานนี้ถ้าคุณต้องการเริ่มต้นกับการตรวจสอบฝั่งเซิร์ฟเวอร์ สำหรับบทช่วยสอนทั้งหมดโปรดไปที่หน้านี้

โชคดี!


4

ดังที่กล่าวไว้ในคำตอบก่อนหน้านี้เราไม่สามารถ จำกัด ให้ผู้ใช้เลือกไฟล์สำหรับรูปแบบไฟล์ที่กำหนดเท่านั้น แต่มันมีประโยชน์มากที่จะใช้แท็ก accept บนไฟล์ใน html

สำหรับการตรวจสอบเราต้องทำที่ฝั่งเซิร์ฟเวอร์ เราสามารถทำได้ที่ด้านลูกค้าใน js แต่ไม่ใช่วิธีแก้ปัญหาที่เข้าใจไม่ได้ เราต้องตรวจสอบที่ฝั่งเซิร์ฟเวอร์

สำหรับความต้องการเหล่านี้ฉันชอบเฟรมเวิร์กการพัฒนาเว็บแอ็พพลิเคชัน Java ของ struts2 จริง ๆ ด้วยคุณสมบัติการอัปโหลดไฟล์ในตัวการอัปโหลดไฟล์ไปยังแอปพลิเคชั่นบนเว็บ struts2 จึงเป็นเรื่องง่าย เพียงแค่พูดถึงรูปแบบไฟล์ที่เราต้องการยอมรับในแอปพลิเคชันของเราและส่วนที่เหลือทั้งหมดจะได้รับการดูแลโดยแกนหลักของเฟรมเวิร์กนั้นเอง คุณสามารถตรวจสอบได้ที่เว็บไซต์อย่างเป็นทางการของเสา


3

ฉันอาจแนะนำต่อไปนี้:

  • หากคุณต้องให้ผู้ใช้เลือกไฟล์ภาพใด ๆ โดยค่าเริ่มต้นการใช้ accept = "image / *"

    <input type="file" accept="image/*" />

  • หากคุณต้องการ จำกัด ประเภทภาพบางประเภทให้ใช้ accept = "image / bmp, image / jpeg, image / png"

    <input type="file" accept="image/bmp, image/jpeg, image/png" />

  • ถ้าคุณต้องการ จำกัด เฉพาะบางประเภทให้ใช้ accept = ". bmp, .doc, .pdf"

    <input type="file" accept=".bmp, .doc, .pdf" />

  • คุณไม่สามารถ จำกัด ผู้ใช้ให้เปลี่ยนไฟล์ตัวกรองเป็นไฟล์ทั้งหมดได้ดังนั้นควรตรวจสอบประเภทไฟล์ในสคริปต์และเซิร์ฟเวอร์เสมอ


1
นี่คือสิ่งที่ฉันกำลังมองหา: accept = ". bmp" ทำงานได้ดีบนโครม
MichaelRom
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.