< BACK TO BLOG

Detect File-type in vanilla javascript: Cloudflare workers

Published Tue Oct 03 2023



code snippet to detect file type in vanilla javascript





// Example object mapping MIME types to magic numbers and extensions
const mimeTypesData = {
  'image/jpeg': {
    magicNumbers: [0xFF, 0xD8],
    extension: '.jpg',
  },
  'image/png': {
    magicNumbers: [0x89, 0x50],
    extension: '.png',
  },
  'image/gif': {
    magicNumbers: [0x47, 0x49, 0x46],
    extension: '.gif',
  },
  'image/bmp': {
    magicNumbers: [0x42, 0x4D],
    extension: '.bmp',
  },
  'image/tiff': {
    magicNumbers: [0x49, 0x49, 0x2A, 0x00],
    extension: '.tiff',
  },
  'image/webp': {
    magicNumbers: [0x52, 0x49, 0x46, 0x46, null, null, null, null, 0x57, 0x45, 0x42, 0x50],
    extension: '.webp',
  },
  'image/svg+xml': {
    magicNumbers: [0x3C, 0x3F, 0x78, 0x6D, 0x6C],
    extension: '.svg',
  },
  'image/x-icon': {
    magicNumbers: [0x00, 0x00, 0x01, 0x00],
    extension: '.ico',
  },
  'image/heif': {
    magicNumbers: [0x00, 0x00, 0x00, 0x14, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63],
    extension: '.heif',
  },
  'image/x-raw': {
    magicNumbers: [0x49, 0x49, 0x2A, 0x00],
    extension: '.raw',
  },
  'video/mp4': {
    magicNumbers: [0x66, 0x74, 0x79, 0x70, 0x33, 0x67, 0x70, 0x34],
    extension: '.mp4',
  },
  'video/webm': {
    magicNumbers: [0x1A, 0x45, 0xDF, 0xA3],
    extension: '.webm',
  },
  'video/avi': {
    magicNumbers: [0x52, 0x49, 0x46, 0x46, null, null, null, null, 0x41, 0x56, 0x49, 0x20],
    extension: '.avi',
  },
  'video/x-matroska': {
    magicNumbers: [0x1A, 0x45, 0xDF, 0xA3],
    extension: '.mkv',
  },
  'video/quicktime': {
    magicNumbers: [0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x6D, 0x70, 0x34, 0x32],
    extension: '.mov',
  },
  'video/x-ms-wmv': {
    magicNumbers: [0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9, 0x00, 0xAA],
    extension: '.wmv',
  },
  'video/x-flv': {
    magicNumbers: [0x46, 0x4C, 0x56, 0x01],
    extension: '.flv',
  },
  'video/3gpp': {
    magicNumbers: [0x66, 0x74, 0x79, 0x70, 0x33, 0x67, 0x70],
    extension: '.3gp',
  },
  'video/mpeg': {
    magicNumbers: [0x00, 0x00, 0x01, 0xBA],
    extension: '.mpeg',
  },
  'video/ogg': {
    magicNumbers: [0x4F, 0x67, 0x67, 0x53],
    extension: '.ogg',
  },
  'video/vob': {
    magicNumbers: [0x00, 0x00, 0x01, 0xBA],
    extension: '.vob',
  },
  'video/x-m4v': {
    magicNumbers: [0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x4D, 0x34, 0x56],
    extension: '.m4v',
  },
  'application/x-shockwave-flash': {
    magicNumbers: [0x43, 0x57, 0x53],
    extension: '.swf',
  },
};


// ... (MIME types and magic numbers data)


// Function to determine the file extension from a file buffer
function getFileExtensionFromBuffer(fileBuffer) {
  // Ensure fileBuffer is a Uint8Array (arrayBuffer() result)
  if (!(fileBuffer instanceof Uint8Array)) {
    throw new Error('fileBuffer is not a Uint8Array');
  }


  // Get the first few bytes from the buffer
  const firstBytes = Array.from(fileBuffer.slice(0, 8)); // Check up to 12 bytes


  // Check if the first bytes match any known magic numbers
  for (const mimeType in mimeTypesData) {
    const mimeTypeData = mimeTypesData[mimeType];
    const magicBytes = mimeTypeData.magicNumbers;
    if (magicBytes.every((value, index) => (value === null ? true : value === firstBytes[index]))) {
      return mimeTypeData.extension;
    }
  }


  // If no known magic numbers match, return a default extension
  return '.bin'; // Default to binary data if unknown
}


export default {
  async fetch(request, env) {
    try {
      const url = new URL(request.url);
      const key = url.pathname.slice(1);


      switch (request.method) {
        case 'POST':
          const fileBuffer = new Uint8Array(await request.arrayBuffer());
          return new Response(JSON.stringify({


            // typeof: typeof fileBuffer,//
            // fileBuffer,
            filename123: `${crypto.randomUUID()}${getFileExtensionFromBuffer(fileBuffer)}`,
          }));


        // ... (other cases)


        default:
          return new Response('Method Not Allowed', {
            status: 405,
            headers: {
              Allow: 'PUT, GET, DELETE',
            },
          });
      }
    } catch (e) {
      return new Response(JSON.stringify(e.stack || e), {
        status: 400,
      });
    }
  },
};





Subscribe to my Newsletter

Get the latest posts delivered right to your inbox