الحقل file

من موسوعة حسوب
< HTML‏ | input
اذهب إلى: تصفح، ابحث

عناصر <input> ذات النوع file تسمح للمستخدم باختيار ملف أو أكثر لرفعها إلى الخادوم أو تعديلها باستخدام الواجهة البرمجية File.

الخاصية value

تحتوي الخاصية value في الحقل file على سلسلة نصية (DOMString) التي تُمثِّل المسار إلى الملف (أو الملفات) المختارة. بعض الأمور التي عليك أن تضعها بالحسبان:

  • إذا تم اختيار عدِّة ملفات، فقيمة الخاصية value ستُمثِّل أوّل ملف مختار، لكن يمكن الوصول إلى الملفات الأخرى عبر الخاصية FileList في DOM التابعة للعنصر <input>.
  • إذا لم يتم اختيار ملف بعد، فستكون قيمة الخاصية value فارغةً.
  • سيتم إسباق السلسلة النصية بالمسار C:\fakepath\ لمنع البرمجيات الخبيثة من معرفة بنية نظام الملفات عند المستخدم.

استخدام حقل رفع الملفات

حقل رفع ملفات بسيط

<form>
 <div>
   <label for="file">اختر ملفًا لترفعه</label>
   <input type="file" id="file" name="file" multiple>
 </div>
 <div>
   <button>رفع</button>
 </div>
</form>
بغض النظر عن جهاز المستخدم أو نظام التشغيل، سيوفِّر هذا الحقل زرًا سيفتح نافذة منتقي الملفات للسماح للمستخدم باختيار ملف.

استخدام الخاصية multiple -كما في المثال أعلاه- سيُمكِّن المستخدم من اختيار أكثر من ملف معًا، ويمكن للمستخدم اختيار عدِّة ملفات في منتقي الملفات بأي طريقة يسمح بها نظام تشغيله (مثلًا: بالضغط على زر Shift أو Ctrl والنقر بالفأرة). إذا كنت تريد أن تسمح للمستخدم باختيار ملف واحد في كل حقل file فاحذف الخاصية multiple.

عند إرسال النموذج في المثال السابق، فسيُضاف اسم كل ملف مُختار إلى رابط URL كما يلي: ‎?file=file1.txt&file=file2.txt.

الحصول على معلومات عن الملفات المختارة

ستُعاد الملفات المختارة عبر الخاصية HTMLInputElement.files، التي ستُعيد الكائن FileList الذي يحتوي على قائمة بكائنات من النوع File، وسيسلك الكائن FileList سلوك مصفوفة، أي بإمكاننا استخدام الخاصية length عليه للحصول على عدد الملفات المختارة.

كل كائن File يحتوي على المعلومات الآتية:

  • name: اسم الملف.
  • lastModified: رقم يُمثِّل التاريخ الذي عُدِّل فيه الملف آخر مرة على شكل بصمة وقت (Unix timestamp).
  • lastModifiedDate: كائن Date يُمثِّل الوقت والتاريخ الذي عُدِّل فيه الملف آخر مرة.
  • size: رقم يُمثِّل حجم الملف التخزيني مقدرًا بالبايت.
  • type: سلسلة نصية (DOMString) تمثِّل نوع MIME للملف.

وضع قيود على أنواع الملفات المسموحة

لن ترغب في أغلبية الأوقات في السماح للمستخدم برفع أيّ نوعٍ يشاء من الملفات، فلو كان حقل رفع الملفات يستخدم لرفع صورة لحساب المستخدم، فربما تريد السماح لأنواع الصور المتوافقة مع الويب مثل JPEG أو PNG فقط.

يمكن تحديد أنواع الملفات التي يقبلها الخادوم باستخدام الخاصية accept، وبقية الأنواع سيتجاهلها المتصفح، يجب أن تكون قيمة هذه الخاصية هي قائمة مفصولة بفاصلة لمُحدِّدات أنواع الملفات الآتية:

  • امتداد الملف الذي يجب أن يبدأ بنقطة (مثل ‎.jpg أو ‎.png أو ‎.doc).
  • نوع MIME صحيح
  • السلسلة النصية audio/*‎ التي تُمثِّل الملفات الصوتية.
  • السلسلة النصية video/*‎ التي تُمثِّل ملفات الفيديو.
  • السلسلة النصية image/*‎ التي تُمثِّل الصور (تسمح العديد من متصفحات الهواتف التقاط الصور عند استخدام هذه القيمة).
هذا مثال عن استخدام حقل رفع الملفات للسماح للمستخدم برفع صورة لحسابه بصيغة JPEG أو PNG:
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="profile_pic">اختر صورةً لترفعها</label>
    <input type="file" id="profile_pic" name="profile_pic"
      accept=".jpg, .jpeg, .png">
  </div>
  <div>
    <button>رفع</button>
  </div>
</form>
إذا حاولت اختيار ملف في المثال السابق فسترى أنَّ منتقي الملفات لا يسمح لك إلا باختيار أنواع الملفات المُحدَّدة عبر الخاصية accept (قد يختلف سلوك منتقي الملفات بين المتصفحات وبين أنظمة التشغيل).

لا تتحقق الخاصية accept من نوع الملفات المُحدَّدة، وإنما توفّر «تلميحةً» للمتصفحات لكي توجِّه المستخدم إلى اختيار نوع الملفات الصحيح، لكن من الممكن (في أغلبية الحالات) أن يتمكن المستخدم من تفعيل خيار في منتقي الملفات لجعل جميع الملفات قابلة للاختيار ومن ثم اختيار نوع ملفات غير صحيح.

وبالتالي علينا أن نحرص على التحقق من نوع الملف بالطرائق المناسبة في جهة الخادوم.

أمثلة

سنُنشِئ في هذا الملف منتقي ملفات متقدم نسبيًا الذي يستفيد من معلومات الملف المتوافرة في خاصية HTMLInputElement.files، وسنستعرض بعض الحيل المفيدة.

يمكنك النظر إلى الشيفرة الكاملة أو تجربة المثال الحي، لكننا لن نشرح أنماط CSS لأن تركيزنا سيكون على JavaScript.

لننظر أوّلًا إلى شيفرة HTML:
<form>
  <div>
    <label for="image_uploads">اختر صورًا لترفعها</label>
    <input type="file" id="image_uploads" name="image_uploads" accept=".jpg, .jpeg, .png" multiple>
  </div>
  <div class="preview">
    <p>لم تُحدَّد ملفات لترفع بعد</p>
  </div>
  <div>
    <button>رفع</button>
  </div>
</form>
الشيفرة السابقة تشبه ما قد سلف، لذا لا حاجة إلى شرحها. أما في شيفرة JavaScript فحصلنا في أوّل عدِّة أسطر منها على مرجعيات إلى عنصر <input> وعنصر <div> ذي الفئة preview. ثم سنخفي الحقل file لأنَّ شكله الافتراضي بشع وغير متناسق في جميع المتصفحات، يمكن تفعيل العنصر بالضغط على العنصر <label> المرتبط معه، لذا من الأفضل -بصريًا- إخفاء الحقل وتنسيق اللافتة الخاصة به لتشبه الزر، لكي يعرف المستخدم أنَّ بإمكانه الضغط عليها إذا أراد رفع الملفات:
var input = document.querySelector('input');
var preview = document.querySelector('.preview');

input.style.opacity = 0;
ملاحظة: استخدمنا الخاصية opacity لإخفاء حقل رفع الملفات بدلًا من visibility: hidden أو display: none لأن التقنيات المساعدة في قابلية الوصول ستُفسِّر آخر خاصيتين على أنهما تجعلان حقل رفع الملفات غير تفاعلي. ثم سنضيف دالة لمعالجة الأحداث المرتبطة بالحقل عندما يتم تغيير قيمته (أي عندما يختار المستخدم بعض الملفات)، وقوع الحدث change سيؤدي إلى استدعاء الدالة updateImageDisplay()‎ التي سنعرفها لاحقًا.
input.addEventListener('change', updateImageDisplay);
عند استدعاء الدالة updateImageDisplay()‎ فستقوم الشيفرة بما يلي:
  • استخدام حلقة while لحذف المحتوى السابق لعنصر <div> الذي يستخدم لعرض مصغرات للصور المرفوعة.
  • الحصول على الكائن FileList الذي يحتوي على معلومات عن جميع الملفات المختارة، وتخزينه في متغير باسم curFiles.
  • التحقق إذا تم اختيار أيّة ملفات، عبر النظر إن كانت قيمة الخاصية curFile.length تساوي 0، فإذا كانت كذلك فستُطبَع رسالة إلى عنصر <div> (الذي يستخدم لعرض المصغرات) تُشير إلى عدم تحديد أيّة ملفات.
  • إذا تم اختيار ملفات، فسنمر عليها كلها بحلقة تكرار ونطبع معلومات عنها في عنصر <div>.
  • لاحظ أننا نستخدم الدالة validFileType()‎ للتأكد أنَّ نوع الملف صحيح (أي أنَّه صورة).
  • إذا كان نوع الملف صالحًا، فسوف:
    • نطبع اسمه وحجمه التخزيني داخل العنصر <div> (سنحصل عليهما من الخاصيتين curFiles[i].name و curFiles[i].size)، الدالة returnFileSize()‎ ستُعيد حجم الملف بعد تنسيقه بصيغة مقروءة (مع وضع الواحدة bytes أو KB أو MB) فالمتصفحات تُعيد حجم الملف بواحدة البايت دومًا.
    • توليد مُصغرات للصور باستدعاء الدالة ‎window.URL.createObjectURL(curFiles[i])‎ وتقليل حجم الصورة باستخدام CSS ثم إضافة الصورة في القائمة أيضًا.
  • أما إذا كان نوع الملف غير صالح، فسنعرض رسالة ضمن القائمة تخبر المستخدم بأن يختار ملفًا من النوع الصحيح.
function updateImageDisplay() {
  while(preview.firstChild) {
    preview.removeChild(preview.firstChild);
  }

  var curFiles = input.files;
  if(curFiles.length === 0) {
    var para = document.createElement('p');
    para.textContent = 'No files currently selected for upload';
    preview.appendChild(para);
  } else {
    var list = document.createElement('ol');
    preview.appendChild(list);
    for(var i = 0; i < curFiles.length; i++) {
      var listItem = document.createElement('li');
      var para = document.createElement('p');
      if(validFileType(curFiles[i])) {
        para.textContent = 'File name ' + curFiles[i].name + ', file size ' + returnFileSize(curFiles[i].size) + '.';
        var image = document.createElement('img');
        image.src = window.URL.createObjectURL(curFiles[i]);

        listItem.appendChild(image);
        listItem.appendChild(para);

      } else {
        para.textContent = 'File name ' + curFiles[i].name + ': Not a valid file type. Update your selection.';
        listItem.appendChild(para);
      }

      list.appendChild(listItem);
    }
  }
}
الدالة validFileType()‎ تأخذ الكائن File كوسيط، ثم ستمر على مصفوفة بأنواع الملفات المسموحة وتتحقق من مطابقة نوع الملف لأحدها، وإن عُثِرَ على مُطابقة فستعيد الدالة القيمة true وإلا فستُعيد false.
var fileTypes = [
  'image/jpeg',
  'image/pjpeg',
  'image/png'
]

function validFileType(file) {
  for(var i = 0; i < fileTypes.length; i++) {
    if(file.type === fileTypes[i]) {
      return true;
    }
  }

  return false;
}
تأخذ الدالة returnFileSize()‎ عددًا (مُقدرًا بالبايت، ومأخوذًا من الخاصية size) وتحوِّله إلى حجم سهل القراءة:
function returnFileSize(number) {
  if(number < 1024) {
    return number + 'bytes';
  } else if(number > 1024 && number < 1048576) {
    return (number/1024).toFixed(1) + 'KB';
  } else if(number > 1048576) {
    return (number/1048576).toFixed(1) + 'MB';
  }
}

دعم المتصفحات

Chrome Firefox Edge Safari Opera
مدعوم مدعوم مدعوم مدعوم مدعوم