Mensagens instantâneas entre usuários do GLPI 10.
Chat flutuante em qualquer página, página completa de conversas, anexos, reações, indicador de digitação, confirmação de leitura e notificações — sem depender de serviço externo.
| Item | Versão |
|---|---|
| GLPI | 10.0.0 – 11.0.x |
| PHP | 7.4+ (extensão fileinfo obrigatória) |
| Banco | MySQL 5.7+ / MariaDB 10.3+ |
O diretório files/_plugins (GLPI_PLUGIN_DOC_DIR) precisa ter permissão de
escrita — é onde os anexos são gravados.
- Copie a pasta
messengerparaglpi/plugins/. - Em Configurar → Plugins, instale e ative o Messenger.
- Ajuste as opções em Configurar → Plugins → Messenger (ícone de engrenagem).
A instalação detecta o esquema antigo e migra automaticamente, preservando todo o histórico de mensagens:
glpi_plugin_messenger→glpi_plugin_messenger_messagessender_id→users_id_sender,receiver_id→users_id_recipient,message→content,date→date_creation- as foreign keys da v1 são removidas (impediam a migração em alguns MySQL)
- índices novos são criados para as consultas de conversa e de não lidas
Anexos antigos continuam acessíveis, mas agora exigem login. O diretório
uploads/ da v1 recebe um .htaccess que bloqueia acesso HTTP direto.
Os endpoints antigos (send_message.php, check_new_messages.php, etc.)
continuam existindo como camada de compatibilidade — já corrigidos.
- Chat flutuante em qualquer página do GLPI (até 5 conversas simultâneas)
- Página completa em Ferramentas → Messenger (lista de conversas + histórico)
- Painel de contatos no botão flutuante, com busca
- Histórico paginado (rolagem infinita para cima)
- Anexos com validação de extensão e de conteúdo real (MIME)
- Reações com emoji, editar (15 min) e excluir mensagem
- "Está digitando", presença online e confirmação de leitura
- Contador de não lidas no botão e no título da aba
- Notificação do navegador e som quando a aba está em segundo plano
- Tema claro/escuro do GLPI 10 e layout responsivo
- Limpeza automática via tarefa agendada (retenção configurável)
Configurar → Plugins → Messenger
| Opção | Padrão | Observação |
|---|---|---|
| Intervalo de verificação | 4000 ms | limitado entre 2 s e 60 s |
| Liberar chat para todos os usuários | Sim | se "Não", exige direito de leitura em Usuários |
| Permitir anexos | Sim | |
| Tamanho máximo por anexo | 10 MB | limitado a 100 MB |
| Extensões permitidas | jpg, png, pdf, docx, xlsx… | extensões executáveis são sempre bloqueadas |
| Permitir editar / excluir | Sim | edição válida por 15 minutos |
| Permitir reações | Sim | conjunto fechado de 7 emojis |
| Notificações / som | Sim | apenas com a aba em segundo plano |
| Ícone de chat nos atores | Sim | ticket, ficha de usuário |
| Excluir mensagens após N dias | 0 (nunca) | executado pela tarefa messengerCleanup |
O intervalo de verificação não precisa ser agressivo: apenas uma aba consulta
o servidor e distribui o resultado para as outras via BroadcastChannel.
setup.php hooks, versão, pré-requisitos
hook.php instalação, migração 1.x → 2.x, desinstalação
config.php compatibilidade v1 (configuração agora vive no banco)
download.php compatibilidade v1 (redireciona para front/download.php)
inc/api.class.php base dos endpoints: auth, CSRF, JSON, lock de sessão
inc/config.class.php configuração + formulário
inc/user.class.php contatos, visibilidade por entidade, nome de exibição
inc/message.class.php envio, histórico, polling, leitura, edição, cron
inc/attachment.class.php upload validado, autorização, limpeza de órfãos
inc/reaction.class.php reações (lista fechada de emojis)
inc/presence.class.php online e "está digitando"
inc/messenger.class.php shim depreciado da classe da v1
ajax/bootstrap.php usuário, configuração e cursor inicial
ajax/contacts.php lista de contatos
ajax/history.php histórico paginado
ajax/poll.php polling incremental (mensagens, leitura, digitando)
ajax/send.php envio
ajax/read.php marcar como lida
ajax/react.php reação
ajax/message.php editar / excluir
ajax/typing.php heartbeat de digitação
ajax/upload.php upload de anexo
front/messenger.php página completa
front/download.php entrega autenticada de anexos
front/config.form.php página de configuração
scripts/messenger.js front-end completo (sem dependências)
css/messenger.css tema claro/escuro, responsivo
| Tabela | Conteúdo |
|---|---|
glpi_plugin_messenger_messages |
mensagens (texto puro) |
glpi_plugin_messenger_attachments |
anexos (arquivo fora do webroot) |
glpi_plugin_messenger_reactions |
reações |
glpi_plugin_messenger_presences |
presença e digitação (1 linha por usuário) |
glpi_plugin_messenger_configs |
configuração (1 linha) |
Correções em relação à versão 1.x:
| Problema na v1 | Situação atual |
|---|---|
upload_attachment.php aceitava upload sem autenticação e gravava dentro do webroot |
sessão + CSRF obrigatórios; arquivo gravado em GLPI_PLUGIN_DOC_DIR, nome aleatório |
download.php servia qualquer arquivo sem autenticação |
exige login e participação na conversa; mesma resposta 404 para inexistente e sem permissão |
sender_id vinha do cliente — dava para enviar mensagem no nome de outro usuário |
remetente sempre da sessão |
receiver_id vinha do cliente em mark_messages_read.php — dava para marcar mensagens de terceiros |
destinatário sempre da sessão |
conteúdo com HTML era injetado via innerHTML (XSS armazenado) |
conteúdo é texto puro; DOM montado com textContent; links criados como nós <a> validados |
get_user_list.php expunha e-mail, telefone e grupo de todos os usuários, ignorando permissões |
apenas id, nome e foto, restrito às entidades visíveis |
| sem CSRF nas escritas | cabeçalho customizado obrigatório + Sec-Fetch-Site + token do GLPI rotativo |
| sem limite de envio | 30 mensagens/minuto por sessão |
| extensão validada, conteúdo não | extensão + MIME real coerentes; lista negra de executáveis; extensão dupla rejeitada |
onclick inline em HTML gerado |
delegação de eventos (compatível com CSP) |
Anexos são servidos com X-Content-Type-Options: nosniff,
Content-Security-Policy: default-src 'none'; sandbox e apenas imagens e PDF
podem abrir inline — o resto é sempre download.
| Antes | Agora |
|---|---|
| polling a cada 1,5 s retornando todas as não lidas | intervalo configurável, cursor incremental (só o que mudou) |
MutationObserver disparava um fetch da lista completa de usuários a cada alteração do DOM |
observer com debounce e zero requisições |
| sessão do PHP travada durante o polling, serializando toda a navegação | Session::writeClose() nos endpoints de leitura |
| cada aba consultava o servidor | uma aba "líder" consulta e distribui via BroadcastChannel |
| sem backoff em erro | backoff exponencial, pausa quando a aba está oculta ou o usuário está inativo |
SELECT sem índice de conversa |
índices conversation e unread |
| N+1 para anexos e reações | 2 consultas agregadas por página de mensagens |
O chat não aparece.
Verifique se o plugin está ativo e se o usuário atende a "Liberar chat para todos
os usuários". Abra o console do navegador: mensagens do plugin começam com
[messenger].
"Token CSRF ausente". A página foi carregada antes da ativação do plugin. Recarregue com Ctrl+F5.
Anexo não envia.
Confira upload_max_filesize e post_max_size no PHP, a permissão de escrita em
files/_plugins/messenger e se a extensão está na lista permitida.
Mensagens antigas sem data.
A v1 permitia date nulo; a instalação preenche esses registros com a data da
migração.
GPLv3.
Autor original: R&M. Reescrita 2.0 mantendo compatibilidade de dados.