Origem: achados do agente executor durante a implementação do req-137 / BATCH-140, ao rastrear os consumidores do canal
postMessagedo gerenciador de arquivos. Ambos são defeitos pré-existentes, anteriores àquele lote, e por isso foram deixados fora do escopo dele e promovidos para esta requisição por decisão explícita do Engenheiro Chefe Humano.
Descrição do Problema / Contexto
1. O admin-arquivos não devolve MIME type — devolve uma string inventada
O gerenciador de arquivos monta o campo mime por concatenação de rótulo interno com extensão,
em admin-arquivos.php:183:
'mime' => $tipo . '/' . strtolower(pathinfo($nome, PATHINFO_EXTENSION)),Como $tipo vem de arquivo_tipo_por_extensao() e só pode assumir image, video, audio ou
file, o resultado não é um MIME type — é um híbrido que coincide com o MIME real em alguns
casos e diverge em outros:
| Arquivo | Valor atual | MIME real | Situação |
|---|---|---|---|
foto.png |
image/png |
image/png |
coincide por acaso |
video.mp4 |
video/mp4 |
video/mp4 |
coincide por acaso |
foto.jpg |
image/jpg |
image/jpeg |
divergente |
icone.svg |
image/svg |
image/svg+xml |
divergente |
musica.mp3 |
audio/mp3 |
audio/mpeg |
divergente |
manual.pdf |
file/pdf |
application/pdf |
divergente |
dados.json |
file/json |
application/json |
divergente |
Por que isso ainda não quebrou nada: todos os consumidores do canal testam apenas o prefixo
(/^image\//), que está sempre correto para imagens. O sufixo nunca é comparado por ninguém.
Onde já produz efeito visível hoje: o valor é exibido cru ao usuário final em dois pontos —
.widgetImage-tipo (interface-v2.js:480)
e ._html-editor-imagepick-tipo (html-editor-interface.js:1214).
Quem seleciona um PDF lê "file/pdf" na interface.
Risco a prazo: qualquer consumidor futuro que compare MIME exato (=== 'application/pdf'), que
alimente uma tabela de ícones por MIME, ou que persista esse valor como content-type de um asset,
falhará em silêncio.
Ponto único de origem: o mesmo campo mime alimenta os quatro caminhos de despacho do
módulo — seleção individual, galeria modal, conclusão de upload e o despacho em lote do BATCH-140.
Corrigir a origem no PHP conserta todos de uma vez, sem tocar em nenhum consumidor.
2. Comparação sempre falsa derruba o picker de imagem do interface-v2
if (dados.tipo?.match(/image\//) === 'image/') {String.prototype.match() sem a flag g devolve um array (['image/', index: 0, ...]) ou
null — nunca uma string. A comparação estrita com 'image/' é, portanto, sempre falsa.
Consequência: o ramo de sucesso nunca executa. Ao selecionar uma imagem válida no widget de imagem
do interface-v2, o código cai direto no else e exibe o alerta "Not an image" / "Não é uma
imagem", sem preencher os campos nem fechar o modal. Os demais consumidores do mesmo canal usam a
forma correta (/^image\//.test(dados.tipo)), o que confirma o desvio pontual.
Escopo Detalhado das Alterações
1. MIME real na origem (gestor/bibliotecas/arquivo.php + admin-arquivos.php)
-
Criar
arquivo_mime_por_extensao($nome)na bibliotecaarquivo.php, ao lado da já existentearquivo_tipo_por_extensao(), seguindo o mesmo padrão do arquivo (if (!function_exists(...)), docblock e resolução apenas por extensão, sem depender do arquivo em disco). -
Mapear as extensões já classificadas por
arquivo_tipo_por_extensao()(imagens, vídeos, áudios) mais os formatos de documento, arquivo compactado, fonte e texto de uso corrente no gerenciador. -
Fallback para
application/octet-streamem extensão desconhecida ou ausente. -
Substituir a concatenação de
admin-arquivos.php:183pela chamada à nova função. -
Invariante inegociável: toda extensão que
arquivo_tipo_por_extensao()classifica comoimageDEVE receber um MIME iniciado porimage/, sob pena de quebrar de uma vez os seis consumidores que dependem do teste de prefixo. O mesmo vale paravideo/eaudio/.
2. Correção da comparação no interface-v2
-
Substituir
dados.tipo?.match(/image\//) === 'image/'pela forma já usada pelos demais consumidores do canal:dados.tipo && /^image\//.test(dados.tipo). -
Não alterar o restante do fluxo do widget de imagem, o alerta do
elsenem a estrutura do handler.
Plano de Validação e Testes
-
Validação de Sintaxe:
php -lnos PHP alterados enode --checknointerface-v2.js. -
Testes Automatizados:
-
Teste PHP cobrindo o mapa de MIME, o fallback e — obrigatoriamente — a invariante de prefixo contra a lista real de
arquivo_tipo_por_extensao(). -
Teste JS cobrindo a comparação corrigida, incluindo o caso que hoje falha (
image/jpegválido) e a rejeição correta de não-imagem. -
composer testenpx vitest runsem regressão.
-
-
Validação Manual & Visual:
-
Selecionar uma imagem no picker e confirmar que o tipo exibido é o MIME real (
image/jpeg). -
Confirmar que o despacho em lote do BATCH-140 segue funcionando com o MIME normalizado.
-
Confirmar que o widget de imagem do
interface-v2deixa de recusar imagens válidas.
-