MIME (Multipurpose Internet Mail Extensions) type é um padrão utilizado na internet para indicar o tipo de conteúdo de um arquivo.
Originalmente desenvolvido para identificar os tipos de arquivos anexados a e-mails, o MIME type é agora amplamente utilizado em diferentes contextos, como na web, para indicar o tipo de conteúdo de arquivos transmitidos por meio do protocolo HTTP.
Cada tipo de arquivo é associado a um tipo MIME específico, que é representado por uma string. Por exemplo, o tipo MIME para arquivos de texto simples é text/plain, enquanto o tipo MIME para imagens JPEG é image/jpeg
. Existem centenas de tipos MIME padrão que cobrem uma variedade de tipos de arquivos, desde documentos de texto até arquivos de áudio e vídeo.
Nesse artigo veremos como identificar o mime-type
de um arquivo usando C++ tanto em distribuições GNU+Linux e como dica no Windows.
Para conseguirmos esse feitos em distribuições GNU+Linux utilizaremos a biblioteca libmagic.
Ela é a biblioteca utilizada pelo comando file, o qual será incluido o cabeçalho magic.h que é vinculada de forma estática(static).
Para instalar você pode usar o gerenciador de pacotes do seu sistema, alguns exemplos abaixo:
sudo apt install libmagic-dev # Debian, Ubuntu, Mint, ...
sudo pacman -S libmagic # Arch
sudo dnf install file-devel # Fedora
brew install libmagic # macOS
Caso você não encontre no repositório do seu sistema, você pode compilar do zero:
Lembre-se antes de possuir as ferramentas de compilação: gcc, make, além do wget para fazermos o download do tarball.
wget ftp://ftp.astron.com/pub/file/file-5.40.tar.gz
tar -xzf file-5.40.tar.gz
cd file-5.40
./configure
make
sudo make install
Para esse exemplo, vamos ver o mime-type
dessa imagem abaixo que é do formato PNG, faça o download clicando com o botão direito do mouse sobre a imagem e clicando em: Salvar como no diretório que estará o binário do código.
cpp-icon.png
Crie um arquivo main.cpp
e cole o código abaixo:
O código está devidamente comentado explicando cada bloco de código para elucidar ações.
// Inclui a libmagic e iostream para escrever na saída padrão
#include <iostream>
#include <magic.h>
int main() {
// Inicia o cookie
magic_t magic_cookie;
// Informa o arquivo que queremos ver o mime-type
const char *file_path = "cpp-icon.png";
// Inicializa a libmagic
magic_cookie = magic_open(MAGIC_MIME_TYPE);
if (magic_cookie == NULL) {
std::cerr << "Não foi possível inicializar a libmagic\n";
return 1;
}
// Carrega as definições do banco de dados de mime types
if (magic_load(magic_cookie, NULL) != 0) {
std::cerr << "Não foi possível carregar as definições do banco de dados\n";
magic_close(magic_cookie);
return 1;
}
// Determina o MIME type do arquivo
const char *mime_type = magic_file(magic_cookie, file_path);
if (mime_type == NULL) {
std::cerr << "Não foi possível determinar o MIME type do arquivo\n";
magic_close(magic_cookie);
return 1;
}
std::cout << "MIME type do arquivo: " << mime_type << "\n";
// Fecha a libmagic
magic_close(magic_cookie);
return 0;
}
Feito isso, é só compilarmos, é necessário passar a flag -lmagic
e rodar:
g++ main.cpp -lmagic
./a.out
A possível e provavel saída será:
MIME type do arquivo: image/png
Note que se alterarmos a extensão do arquivo para uma extensão qualquer, mesmo o gerenciador de arquivos exibindo um ícone referente a extensão, a libmagic é segura e correta em relação a isso, mostrará qual o verdadeiro mime-type daquele arquivo.
Isso acontece muito em sistemas que pessoas mal intencinadas querem executar código na Web e a página pede para carregar somente arquivo: jpeg e png, mas alteram só a extensão, mas na verdade o arquivo é um script.
Se eu renomear o arquivo para .mp4
, por exemplo:
mv cpp-icon.png cpp-icon.mp4
E alterar no código para carregar o cpp-icon.mp4
:
const char *file_path = "cpp-icon.mp4";
Após compilar e rodar, você verá que a libmagic exibirá o Mime-Type CORRETO! E não o da extensão.
No Windows, você pode usar a urlmon.h
com o código abaixo:
#include <iostream>
#include <urlmon.h>
#include <windows.h>
#pragma comment(lib, "urlmon.lib")
int main() {
LPCWSTR file_path = L"caminho_do_arquivo";
LPWSTR mime_type = NULL;
HRESULT hr = FindMimeFromData(NULL, file_path, NULL, 0, NULL, 0, &mime_type,
0); if (SUCCEEDED(hr) && mime_type != NULL) { std::wcout << L"MIME type do
arquivo: " << mime_type << std::endl; CoTaskMemFree(mime_type); } else {
std::cerr << "Não foi possível determinar o MIME type do arquivo\n";
}
return 0;
}
Lembrando que para você conseguir compilar, você precisa habilitar a urlmon.dll
no Registro do Windows, como descreve nesse link.
Existem diversas “bibliotecas” C++ no GitHub que faz um FAKE MIME-TYPE, ou seja, se fizermos o procedimento que descrevemos acima de renomear a extensão do arquivo, essas “bibliotecas”, nos informa o incorreto mime-type. Isso é inseguro e perigoso!
Por exemplo, encontrei essa aqui https://github.com/lasselukkari/MimeTypes, se você clonar:
git clone https://github.com/lasselukkari/MimeTypes
Usar esse exemplo após renomear a extensão:
#include <iostream>
#include "MimeTypes/MimeTypes.h"
int main(){
std::cout << MimeTypes::getType("./cpp-icon.mp4") << '\n';
return 0;
}
Compile seu arquivo e o MimeTypes.cpp
desse repositório:
g++ main.cpp MimeTypes/MimeTypes.cpp
Após rodar, note que ela informará incorretamente o tipo MIME do arquivo:
video/mp4
Isso não ocorre com a libmagic
!
Nem todos os repositórios no GitHub fazem um fake mime-type, mas fiquem atentos para esses casos!