Em resumo: O mod_php é o PHP como módulo no servidor web Apache. Cada processo do Apache contém então um interpretador PHP completo e executa ele próprio o código PHP; a SAPI chama-se apache2handler. É simples de configurar, mas prende o PHP ao Apache, exige em geral o MPM prefork e quase não permite separação entre sites. O manual do PHP desaconselha-o para novas instalações e, no PHP2Shell, a equipa do PHP classifica o risco como o mais elevado no mod_php.
O que é o mod_php?
No mod_php, o Apache carrega o PHP como módulo próprio nos seus processos. Não há um serviço PHP separado: quando o Apache tem de entregar um ficheiro .php, é o mesmo processo que aceitou o pedido que executa também o código PHP. Durante muitos anos foi a via normal de operar o PHP e, ainda hoje, está muito difundido em servidores mais antigos e em algumas imagens Docker.
Segundo o manual do PHP, como módulo de servidor o PHP lê a sua configuração apenas uma vez, no arranque do servidor web. As alterações ao php.ini e as atualizações do módulo só fazem efeito, por isso, depois de um reinício do Apache.
Importante para a compreensão: os processos do Apache têm vida longa. Um processo aceita muitas ligações em sequência antes de ser substituído; quantas, regula-o a diretiva Apache MaxConnectionsPerChild. O interpretador PHP incorporado mantém-se o mesmo durante esse tempo. Quem substitui a biblioteca libphp no disco não altera nada nos processos em execução.
Para a gerência e os responsáveis de projeto, pode resumir-se assim: no mod_php, o servidor web e o PHP são uma unidade. Quem mexe num afeta o outro. Uma atualização do PHP significa um reinício do servidor web, uma falha no PHP corre com as permissões do servidor web e uma separação entre vários sites no mesmo servidor é quase impossível.
Como se integra o mod_php?
O manual do PHP mostra a integração em dois passos: carregar o módulo e definir que ficheiros o PHP deve processar.
LoadModule php_module modules/libphp.so
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>
O manual recomenda FilesMatch com SetHandler em vez de apenas AddType, para que ficheiros carregados como bild.php.jpg não sejam executados como PHP. No Debian e no Ubuntu, pacotes como libapache2-mod-php8.3 e os comandos a2enmod e a2dismod tratam deste trabalho.
Se o mod_php está ativo pode verificar-se apenas em leitura:
apachectl -M 2>/dev/null | grep -i php # Debian/Ubuntu
httpd -M 2>/dev/null | grep -i php # família RHEL
apachectl -V | grep -i mpm # MPM ativo (prefork, worker, event)
Prefork, Thread Safety e recursos
O Apache distribui os pedidos através de um módulo de multiprocessamento (MPM). Segundo o manual do PHP, o mod_php necessita do MPM prefork, a menos que o PHP tenha sido compilado com Zend Thread Safety (--enable-zts). A maioria dos pacotes das distribuições é compilada sem Thread Safety.
Prefork significa: um processo por ligação simultânea, e cada processo transporta um interpretador PHP completo. Até os pedidos de imagens ou de ficheiros CSS ocupam assim um processo com o PHP às costas. Isto custa memória e limita a carga que um servidor consegue suportar.
| Característica | mod_php | PHP-FPM |
|---|---|---|
| Onde corre o PHP? | em cada processo do Apache | em serviço próprio |
| MPM do Apache | em geral prefork |
event possível |
| Utilizador por site | não, tudo como utilizador do Apache | sim, por pool |
| Reiniciar o PHP | só com o Apache | independente do Apache |
| Definições por diretório | php_value no .htaccess |
pool ou .user.ini |
O manual recomenda por isso, para todas as instalações modernas, o PHP-FPM com mod_proxy_fcgi: melhor gestão de recursos, separação de processos, reinício do PHP sem reiniciar o Apache e compatibilidade com o MPM event, que é o padrão desde o Apache 2.4. Os fundamentos estão em PHP-FPM explicado.
Definições com .htaccess, php_value e php_admin_value
Com o mod_php, as definições do PHP podem ser fixadas diretamente na configuração do Apache. O manual distingue aqui modos de alteração: as entradas com INI_PERDIR podem constar do php.ini, do .htaccess ou do httpd.conf; as entradas com INI_SYSTEM, apenas do php.ini ou do httpd.conf.
# Na configuração do VirtualHost: bloqueado para a aplicação
php_admin_flag display_errors off
php_admin_value upload_max_filesize 24M
# Possível no .htaccess, mas a aplicação pode sobrescrever
php_value max_execution_time 60
php_admin_value e php_admin_flag só são permitidos na configuração do servidor, não no .htaccess. É precisamente esta distinção que importa nas medidas transitórias contra o PHP2Shell, porque valores como session.upload_progress.enabled não podem ser repostos pela aplicação.
mod_php e PHP2Shell: porque é que o risco é o mais elevado
A equipa do PHP classifica o risco do PHP2Shell como o mais elevado no mod_php: aí foi demonstrado um exploit antes de qualquer código de aplicação correr. Plugins de segurança ou verificações no CMS chegam, assim, tarde demais. Acresce que, no mod_php, o PHP corre com as permissões e na memória do servidor web. O enquadramento detalhado está em Porque é que o mod_php tem o risco mais elevado.
Para os operadores vale por isso:
- Atualizar o módulo PHP para 8.5.12, 8.4.27, 8.3.36 ou 8.2.35, ou para um backport confirmado.
- Reiniciar o Apache por completo, não apenas recarregar, e verificar a hora de arranque dos processos.
- Definir os valores transitórios com
php_admin_valuena configuração do servidor, se a atualização ainda não for possível. - Depois, planear a mudança para o PHP-FPM, como descrito em Proteger o Apache com mod_php.
Como ajuda concretamente a PHP SOS?
- Reconhecer: Verificamos em que servidores corre o mod_php, com que MPM e a partir de que fonte de pacotes.
- Aplicar patches: Atualizamos o módulo PHP, reiniciamos o Apache por completo e comprovamos o estado.
- Proteger a fase transitória: Onde a atualização está bloqueada, definimos as medidas do php.net como bloqueadas na configuração do servidor.
- Migrar: No âmbito do reforço de servidores, migramos de forma testada para o PHP-FPM com pools próprios.
Perguntas frequentes
Porque é que se chama mod_php, se o módulo se chama php_module?
mod_php é o nome corrente para o PHP como módulo do Apache. Na configuração é carregado com LoadModule; o manual do PHP dá como exemplo LoadModule php_module modules/libphp.so. Versões mais antigas usavam nomes como php7_module ou php5_module.
Porque é que o mod_php precisa do MPM prefork?
Segundo o manual do PHP, o mod_php necessita do MPM prefork, a menos que o PHP tenha sido compilado com Zend Thread Safety. A maioria dos pacotes das distribuições é compilada sem Thread Safety. O prefork inicia um processo próprio para cada ligação simultânea, o que exige mais memória.
As linhas php_value no .htaccess também funcionam com o PHP-FPM?
Não. O php_value e o php_flag no .htaccess são diretivas Apache do módulo PHP e só atuam com o mod_php. No PHP-FPM, essas definições pertencem ao pool ou, para os valores permitidos, a um .user.ini.
Tenho de abandonar o mod_php de imediato?
Primeiro vem a atualização do PHP com reinício completo do Apache. A mudança para o PHP-FPM é depois aconselhável, mas deve ser planeada e testada. Não resolve o PHP2Shell, porque o PHP-FPM também está afetado.