Към съдържанието
PN Scripts

Разработка

Правилната икона на файл по името или MIME типа му

  • PN Scripts
  • 7 мин четене

Списък с файлове с правилната икона до всяко име се чете с един поглед: PDF файлът е червен, таблицата зелена, архивът кафяв. Списък, в който половината икони са празен лист, се чете ред по ред. Празните листове идват от няколко познати случая: REPORT.PDF с главни букви, backup.tar.gz, показан като обикновен gzip файл, снимка от телефон с име IMG_0042 без никакво разширение, CSV файл, който браузърът нарича файл на Excel, и MIME тип с ; charset=utf-8 в края. Тук показваме откъде всъщност идва типът на файла, ред от правила, който дава правилната икона във всички тези случаи, и страната на сървъра, където иконата е най-малката грижа. JavaScript е пуснат на Node 22, а PHP на PHP 8.4, точно както са отпечатани.

#Откъде идва типът

Източниците са три и нито един от тях сам по себе си не е истината.

  • Името. Разширението е избрано от този, който е кръстил файла. Обикновено е вярно и е единственото, с което разполагате за файл в списък, който не сте отворили.
  • MIME типът от браузъра. File.type в браузъра не се чете от файла. Справочникът на MDN казва, че той се предполага по разширението, че необичайните разширения дават празен низ и че настройките на системата, например регистърът на Windows, могат да дадат неочаквани стойности дори за обичайни типове. Затова файл .csv от компютър с Windows и инсталиран Excel често пристига като application/vnd.ms-excel. При изпращане на формата същата стойност отива на сървъра като Content-Type на частта.
  • Байтовете. Само сървърът може да погледне във файла, с библиотека като finfo в PHP, която разпознава форматите по първите им байтове.

#Ред от правила, който работи

За иконата най-добрият източник е името, а MIME типът е резервата. Проверявайте ги в този ред: име, завършващо с наклонена черта, е папка; после двойните разширения като .tar.gz; после последното разширение с малки букви, което покрива и файлове с точка отпред като .env; после точния MIME тип без параметрите му; после семейството на MIME типа, така че всяко image/... получава обща икона за изображение; и едва накрая общ файл.

const EXT = { pdf: "pdf", docx: "docx", xlsx: "xlsx", csv: "csv", png: "png", jpg: "jpg", jpeg: "jpg",
  heic: "heic", mp4: "mp4", zip: "zip", tgz: "tgz", json: "json", env: "env" };
const DOUBLE = { "tar.gz": "tgz", "tar.bz2": "bz2", "tar.xz": "xz" };
const MIME = { "application/pdf": "pdf", "image/heic": "heic", "text/csv": "csv",
  "application/vnd.ms-excel": "xls", "application/zip": "zip" };
const FAMILY = ["image", "audio", "video", "text", "font", "model"];

export function iconName(fileName, mime = "") {
  const name = String(fileName);
  if (name.endsWith("/")) return "folder";
  const base = name.split(/[\\/]/).pop().toLowerCase();
  for (const [double, icon] of Object.entries(DOUBLE)) {
    if (base.endsWith("." + double)) return icon;
  }
  const dot = base.lastIndexOf(".");
  if (dot >= 0 && Object.hasOwn(EXT, base.slice(dot + 1))) return EXT[base.slice(dot + 1)];
  const type = mime.split(";")[0].trim().toLowerCase();
  if (Object.hasOwn(MIME, type)) return MIME[type];
  const family = type.split("/")[0];
  return FAMILY.includes(family) ? `kind-${family}` : "kind-file";
}

Таблиците тук са съкратени за примера; истински набор покрива доста над сто разширения. Пуснахме го върху десет имена:

  • Annual report 2026.PDF без тип дава pdf: разширението с главни букви пак се брои.
  • backup.tar.gz дава tgz, а не иконата за gzip, защото двойните разширения се проверяват първи.
  • IMG_0042 с image/heic дава heic: няма разширение, затова решава точният MIME тип.
  • prices.csv с application/vnd.ms-excel дава csv: името печели пред догадката на браузъра.
  • scan.weird с image/x-portable-anymap дава kind-image, а голото notes без тип дава kind-file.
  • photos/ е папка, .env дава env, път от Windows, завършващ на Отчет.docx, дава docx, а data с text/csv; charset=utf-8 дава csv.

Един малък детайл е важен: търсенето ползва Object.hasOwn(). С обикновено ext in EXT файл с име x.constructor би намерил собствената функция constructor на обекта и би я върнал като име на икона. С hasOwn той получава общата икона.

#На сървъра иконата е етикет, а не проверка

След качване можете да направите повече от името, защото имате байтовете. Прочетете типа от съдържанието, покажете го до името и дръжте двете решения отделно: иконата следва името, защото него вижда и разпознава човекът; дали файлът се приема, пази и сервира, следва разпознатия тип и другите ви проверки.

<?php

// The type a browser sends with an upload comes from the client; read the file itself instead.
function detected_type(string $path): string
{
    return (new finfo(FILEINFO_MIME_TYPE))->file($path) ?: 'application/octet-stream';
}

function icon_row(string $originalName, string $storedPath, string $iconBase = '/icons/'): string
{
    $type = detected_type($storedPath);
    $icon = icon_name($originalName, $type);   // the same rules as the JavaScript above
    $name = htmlspecialchars($originalName, ENT_QUOTES);

    return sprintf('<li><img src="%s%s.svg" width="24" height="24" alt=""> %s <small>%s</small></li>',
        $iconBase, $icon, $name, htmlspecialchars($type, ENT_QUOTES));
}

icon_name() е PHP версия на функцията на JavaScript по-горе. Пуснахме icon_row() върху малък PNG, качен два пъти. С име holiday "photo", без разширение, той получава иконата за изображение от разпознатия тип image/png, а кавичките в името излизат екранирани. С име <script>.pdf получава иконата за PDF от името си, докато дребният текст казва image/png, а името се показва като текст, а не се изпълнява като таг. Икона на PDF върху PNG е безобидна в списък; да оставите името да реши какво е файлът, не би било. Наръчникът на OWASP за качване на файлове отива по-далеч: позволявайте само списък от разширения, не вярвайте на заглавката Content-Type, защото лесно се подправя, проверявайте и сигнатурата на файла, но не само нея, и пазете файловете под имена, които приложението ви генерира.

#Как да показвате иконата

  • Когато името на файла е написано до иконата, иконата е декоративна: дайте ѝ празен alt="", както препоръчва ръководството на W3C за изображения, за да не четат екранните четци „PDF, Annual report 2026.PDF“.
  • Задайте width и height на изображението, за да не подскача списъкът, докато иконите се зареждат.
  • За дълъг списък един SVG спрайт с <use href="#pdf"> е една заявка вместо по една за всяка икона, а контурен стил, рисуван в currentColor, следва цвета на текста, и в тъмен режим.
  • Ако иконата показва разширението като текст, този текст има нужда от контраст като всеки друг: 4,5:1 за нормален текст по WCAG 2.2.

#Набор от икони с помощниците

Направихме Faylche, набор от 202 икони за типове файлове: по една за 172 разширения, по една за 28 вида файлове и две папки, в четири стила (бял лист с цветен етикет, плътен цвят, контур в currentColor и малък стил, рисуван за 16 и 24 пиксела), като SVG, готови PNG файлове и спрайтове. Помощниците му на JavaScript и PHP следват точно реда от правила по-горе, със 77 точни MIME типа, а тестовете проверяват, че JavaScript, PHP и изграждането на Python дават един и същ отговор за едни и същи имена. Бялото върху всеки цвят и всеки цвят върху листа имат контраст поне 4,5:1. Помощниците са пуснати с Node.js 22 и PHP 8.4 в тестовете; програми за дизайн като Figma не са отваряни. Наборът е обявен като „Очаквайте скоро“.

#Често задавани въпроси

Защо браузърът казва, че моят CSV файл е файл на Excel?

Защото File.type идва от настройките на системата за разширението, а не от файла. В Windows с инсталиран Excel .csv често е регистриран като application/vnd.ms-excel. Решавайте иконата първо по разширението.

Мога ли да вярвам на MIME типа на качен файл?

Не. Типът, изпратен с качването, идва от клиента. Прочетете типа от съдържанието на файла на сървъра, преди да го приемете, запазите или сервирате.

Каква икона да получи файл с непознато разширение?

Ползвайте семейството на MIME типа му, когато го имате, например обща икона за изображение или звук, и обща икона за файл, когато нямате нищо.

Трябва ли иконата на файл да има алтернативен текст?

Не и когато името на файла е написано до нея: тогава иконата е декоративна и alt="" е правилно. Икона, която стои сама, има нужда от текст, който казва какъв е файлът.

#Източници

Още по темата

Още по темата

Коментари

Коментари

Напишете първия коментар.

Оставете коментар

Следваща стъпка

pnscripts.com/bg/contact

Пишете на екипа

Попитайте за статия или ни разкажете за проект, който искате да изградим. Отговаряме до един работен ден.

Пишете ни

Семейството PN Scripts

Другите сайтове на PN Scripts

Хостингът, игрите и блогът имат свои сайтове, поддържани от същата компания.

  • pnscripts.com

    PN Scripts

    Софтуерно инженерство

    Уеб и мобилни приложения, API и игри по поръчка, плюс нашите продукти и плъгини с отворен код.

  • games.pnscripts.com

    Игри

    Игри и игрови сървъри

    Домът на игрите на PN Scripts: безплатни браузърни игри, които се играят веднага, а игровите сървъри предстоят.

  • hosting.pnscripts.com

    Хостинг

    Хостинг и инфраструктура

    Споделен хостинг, KVM VPS, самостоятелни сървъри и домейни от същата компания, която изработва проекта ви.

  • blog.pnscripts.com

    Блог

    Статии и бележки

    Практични статии за разработка на софтуер, хостинг, отворен код и игри, писани от хората, които ги създават.

    Вие сте тук