Situação atual: PHP2Shell. Duas vulnerabilidades críticas do PHP (CVSS 9,2) permitem executar código malicioso sem autenticação. Patches disponíveis desde 21/10/2026.O que fazer agora →

OPcache explicado: a cache de bytecode do PHP

O OPcache mantém na memória partilhada o código PHP já traduzido. Poupa tempo de cálculo, mas exige cuidado em implementações, reinícios e em servidores com vários clientes.

Atualizado em 5 min de leituraConhecimento PHP

Em resumo: O OPcache é a cache de bytecode integrada do PHP. Segundo o manual, guarda bytecode pré-compilado na memória partilhada, de modo que o PHP não tem de carregar e traduzir os scripts a cada pedido. Faz parte da distribuição desde o PHP 5.5.0. O OPcache torna o PHP mais rápido, mas não substitui uma atualização: depois de um patch do PHP, todos os processos PHP têm de ser reiniciados, não basta limpar a cache.

O que faz exatamente o OPcache?

A cada pedido, o PHP tem de ler um script, decompô-lo e traduzi-lo em opcodes, ou seja, nas instruções para a máquina virtual da Zend Engine. Num CMS com centenas de ficheiros, é muito trabalho que se repete constantemente.

O OPcache guarda o resultado desta tradução na memória partilhada (shared memory). Todos os workers de um serviço PHP-FPM, ou todos os processos Apache com mod_php, acedem a ela. Se um ficheiro não muda, o seu bytecode é reutilizado diretamente.

O OPcache é carregado como extensão Zend, não como extensão normal:

; Linux (caminho consoante o pacote)
zend_extension=opcache.so
; Windows
; zend_extension=php_opcache.dll

Segundo o manual, o OPcache deve ser carregado antes do Xdebug quando ambos estão ativos.

É importante saber a quem pertence a memória partilhada. No PHP-FPM, é o processo mestre que a cria e todos os workers de todos os pools desse serviço a utilizam. No mod_php, pertence ao processo principal do Apache. Um reinício do serviço esvazia por isso a cache por completo, ao contrário de um único worker novo. Para a linha de comandos não existe memória partilhada entre chamadas, porque cada chamada é um processo próprio; aí o OPcache está desligado por defeito.

Para quem decide, basta uma regra prática: o OPcache faz quase sempre sentido em servidores de produção, mas exige um procedimento claro para implementações e atualizações.

Que definições do OPcache contam?

Os valores seguintes provêm da página de configuração do manual do PHP. A coluna «Alterável» mostra onde uma definição pode ser fixada: INI_SYSTEM apenas no php.ini ou na configuração do servidor, INI_ALL em qualquer lado.

Diretiva Por defeito Alterável Significado
opcache.enable 1 INI_ALL cache ligada ou desligada, em tempo de execução só se pode desligar
opcache.enable_cli 0 INI_SYSTEM cache para a linha de comandos
opcache.memory_consumption 128 INI_SYSTEM tamanho da memória partilhada em MB
opcache.interned_strings_buffer 8 INI_SYSTEM memória para cadeias de carateres partilhadas em MB
opcache.max_accelerated_files 10000 INI_SYSTEM número máximo de scripts em cache
opcache.validate_timestamps 1 INI_ALL verifica se os ficheiros foram alterados
opcache.revalidate_freq 2 INI_ALL intervalo de verificação em segundos, 0 = a cada pedido
opcache.restrict_api vazio INI_SYSTEM só permite as funções da API a partir de um caminho
opcache.validate_permission 0 INI_SYSTEM verifica as permissões dos ficheiros em relação ao utilizador atual
opcache.validate_root 0 INI_SYSTEM evita colisões de nomes em chroot
opcache.file_cache vazio INI_SYSTEM segundo nível de cache no disco

Uma configuração de produção típica poderia ter este aspeto. Verifique antes os valores com a sua aplicação:

opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.restrict_api=/var/www/admin-tools

Quem define opcache.validate_timestamps=0 ganha um pouco de desempenho. Mas então o OPcache deixa de detetar ficheiros alterados e cada implementação precisa de um reset da cache ou de um reinício.

Observar a cache e limpá-la de forma dirigida

O OPcache traz funções próprias, entre elas opcache_get_status(), opcache_get_configuration(), opcache_invalidate() e opcache_reset(). Uma olhadela curta, apenas de leitura, ao nível de ocupação:

<?php
$status = opcache_get_status(false);
if ($status === false) {
    exit("OPcache ist nicht aktiv.\n");
}
printf("Gecachte Skripte: %d\n", $status['opcache_statistics']['num_cached_scripts']);
printf("Freier Speicher: %.1f MB\n", $status['memory_usage']['free_memory'] / 1048576);

Em servidores com vários sites, nem todas as aplicações devem poder esvaziar ou ler a cache de todas as outras. É para isso que serve o opcache.restrict_api: só os scripts abaixo do caminho indicado podem chamar as funções da API.

JIT: o compilador de código máquina no OPcache

Desde o PHP 8.0, o OPcache contém um compilador JIT que traduz opcodes em código máquina. Segundo o RFC do JIT, é uma parte quase autónoma do OPcache e guarda o código gerado numa área própria da memória partilhada. É controlado através de opcache.jit e opcache.jit_buffer_size. Desde o PHP 8.4.0, o opcache.jit está por defeito em disable. Quando compensa usar o JIT explica-o o artigo JIT e desempenho no PHP 8.

OPcache e segurança: o que vale depois do PHP2Shell

O OPcache não é uma ferramenta de segurança, mas tem consequências para a segurança. Depois do PHP2Shell, três pontos são importantes:

  1. Um reset da cache não é uma atualização. O opcache_reset() só esvazia scripts em cache. O interpretador com as vulnerabilidades CVE-2026-109618 e CVE-2026-109619 permanece na memória até todos os processos serem reiniciados. Como fazê-lo está em Reiniciar o PHP-FPM e todos os workers.
  2. O código injetado pode sobreviver na cache. Se um ficheiro foi manipulado e mais tarde substituído, com a verificação de datas desligada a versão antiga pode continuar a ser executada. Depois de uma limpeza, por isso, faz parte do processo um reinício.
  3. A memória partilhada precisa de separação. Em servidores com vários clientes ajudam pools PHP-FPM próprios por site, bem como opcache.validate_permission e opcache.restrict_api. Um diretório para opcache.file_cache só pode ser gravável pelo utilizador do PHP.
Dica

Depois de cada atualização, verifique se a hora de arranque dos processos PHP é posterior à atualização. Um OPcache cheio com uma taxa de acertos elevada não prova que o novo interpretador está em execução.

Como ajuda concretamente a PHP SOS?

  • Verificar a configuração: Lemos a configuração ativa do OPcache por modo de operação e comparamo-la com a sua aplicação.
  • Proteger as implementações: Estabelecemos um procedimento fixo de reset da cache e reinício, para que nenhuma versão antiga do código continue a correr.
  • Separar clientes: No âmbito do reforço de servidores, definimos pools separados, restrict_api e permissões adequadas.
  • Controlar depois das atualizações: Comprovamos, através das horas de arranque dos processos, que o interpretador atualizado está realmente ativo.

Perguntas frequentes

O OPcache está ativo por defeito?

O OPcache é distribuído com o PHP desde o PHP 5.5.0 e, segundo o manual, funciona com opcache.enable=1 por defeito assim que a extensão está carregada. Se está carregada depende do seu pacote ou alojador. Na linha de comandos, em contrapartida, o OPcache está desligado por defeito (opcache.enable_cli=0).

Porque é que depois de uma implementação ainda vejo o código antigo?

Provavelmente o OPcache só verifica alterações de ficheiros a intervalos ou nunca as verifica. Com opcache.revalidate_freq espera, por defeito, dois segundos; com opcache.validate_timestamps=0, nunca. Nesse caso só ajuda um reset da cache ou um reinício do PHP-FPM ou do Apache.

O opcache_reset() basta depois de uma atualização do PHP?

Não. O opcache_reset() só esvazia a cache de scripts traduzidos. Uma atualização do PHP substitui o próprio interpretador, que está carregado em cada processo em execução. Para isso, todos os processos PHP têm de ser reiniciados.

O JIT está ligado no PHP 8.4?

Segundo o manual, desde o PHP 8.4.0 o opcache.jit está por defeito em disable, enquanto o opcache.jit_buffer_size é de 64M. Antes era o contrário: jit em tracing, buffer a 0. Em ambos os casos, o JIT não está ativo sem uma configuração deliberada.

Fontes

Contacto imediato

Cada hora conta. Escreva-nos agora.

Descreva brevemente o sistema, a versão do PHP e o que observou. Entramos em contacto consigo, esclarecemos a situação e trabalhamos remotamente até o incidente estar concluído e documentado.

Ajuda imediata