强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Apache HTTP Server 完全指南 / PHP 集成

PHP 集成

PHP 是最常用的 Web 开发语言之一。Apache 提供了多种 PHP 集成方式。

1. 集成方式对比

方式模块MPM性能安全推荐
mod_phplibapache2-mod-phpprefork较低
PHP-FPMproxy_fcgievent/worker
FastCGImod_fcgidevent/worker⚠️
CGI无额外模块any

2. mod_php 安装与配置

2.1 安装

# Debian/Ubuntu
sudo apt install libapache2-mod-php8.2
sudo a2enmod php8.2
sudo systemctl restart apache2

# CentOS/RHEL
sudo dnf install php php-mysqlnd php-gd php-mbstring
sudo systemctl restart httpd

2.2 基本配置

# 自动配置(安装后自动生效)
<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

# PHP 配置文件
# /etc/php/8.2/apache2/php.ini

# 重要配置项
# display_errors = Off          # 生产环境关闭显示错误
# error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
# upload_max_filesize = 10M
# post_max_size = 10M
# memory_limit = 256M
# max_execution_time = 30
# max_input_time = 60
# date.timezone = Asia/Shanghai

2.3 优缺点

优点:

  • 配置简单
  • 无需额外进程管理
  • 环境变量自动传递

缺点:

  • 必须使用 prefork MPM
  • 每个连接占用一个进程
  • 内存使用较高
  • 安全性较差(PHP 运行在 Apache 进程中)

3. PHP-FPM 安装与配置

3.1 安装

# Debian/Ubuntu
sudo apt install php8.2-fpm
sudo systemctl start php8.2-fpm
sudo systemctl enable php8.2-fpm

# CentOS/RHEL
sudo dnf install php-fpm
sudo systemctl start php-fpm
sudo systemctl enable php-fpm

# 启用必要模块
sudo a2enmod proxy_fcgi
sudo a2enmod rewrite
sudo systemctl restart apache2

3.2 PHP-FPM 进程池配置

; /etc/php/8.2/fpm/pool.d/www.conf

; 基本设置
[www]
user = www-data
group = www-data

; 监听方式 (Unix Socket - 推荐)
listen = /run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

; 或 TCP 方式
; listen = 127.0.0.1:9000

; 进程管理
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500

; 超时
request_terminate_timeout = 300
request_slowlog_timeout = 5s

; 慢日志
slowlog = /var/log/php-fpm-slow.log

; 安全
security.limit_extensions = .php .php3 .php4 .php5 .php7 .php8

; 环境变量
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

3.3 Apache 配置

# 方法 1:Unix Socket(推荐)
<FilesMatch \.php$>
    SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
</FilesMatch>

# 方法 2:TCP
<FilesMatch \.php$>
    SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>

# 方法 3:使用 ProxyPassMatch
ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/run/php/php8.2-fpm.sock|fcgi://localhost/var/www/html

# 方法 4:目录级别配置
<Directory "/var/www/html">
    <FilesMatch "\.php$">
        SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
    </FilesMatch>
</Directory>

# 多 PHP 版本
<FilesMatch \.php81$>
    SetHandler "proxy:unix:/run/php/php8.1-fpm.sock|fcgi://localhost"
</FilesMatch>

<FilesMatch \.php82$>
    SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
</FilesMatch>

3.4 完整虚拟主机配置

<VirtualHost *:80>
    ServerName www.example.com
    DocumentRoot /var/www/html
    
    <Directory "/var/www/html">
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
        
        # PHP-FPM 配置
        <FilesMatch "\.php$">
            SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
        </FilesMatch>
    </Directory>
    
    # 日志
    ErrorLog /var/log/apache2/example-error.log
    CustomLog /var/log/apache2/example-access.log combined
    
    # PHP 错误日志
    php_flag log_errors on
    php_value error_log /var/log/php/example-error.log
</VirtualHost>

4. 多 PHP 版本管理

4.1 安装多版本

# 添加 PPA(Ubuntu)
sudo add-apt-repository ppa:ondrej/php
sudo apt update

# 安装多个版本
sudo apt install php7.4-fpm php8.0-fpm php8.1-fpm php8.2-fpm

# 检查已安装版本
ls /run/php/
# php7.4-fpm.sock  php8.0-fpm.sock  php8.1-fpm.sock  php8.2-fpm.sock

4.2 按站点配置 PHP 版本

# 站点 A 使用 PHP 8.2
<VirtualHost *:80>
    ServerName site-a.example.com
    DocumentRoot /var/www/site-a
    
    <Directory "/var/www/site-a">
        <FilesMatch "\.php$">
            SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
        </FilesMatch>
    </Directory>
</VirtualHost>

# 站点 B 使用 PHP 7.4(旧应用)
<VirtualHost *:80>
    ServerName site-b.example.com
    DocumentRoot /var/www/site-b
    
    <Directory "/var/www/site-b">
        <FilesMatch "\.php$">
            SetHandler "proxy:unix:/run/php/php7.4-fpm.sock|fcgi://localhost"
        </FilesMatch>
    </Directory>
</VirtualHost>

4.3 使用 .htaccess 切换版本

# 在虚拟主机中允许 .htaccess
<Directory "/var/www/html">
    AllowOverride All
</Directory>
# /var/www/html/.htaccess
<FilesMatch "\.php$">
    SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
</FilesMatch>

5. PHP 配置优化

5.1 php.ini 优化

; /etc/php/8.2/fpm/php.ini

; 错误处理
display_errors = Off
log_errors = On
error_log = /var/log/php/error.log
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT

; 性能
memory_limit = 256M
max_execution_time = 30
max_input_time = 60
max_input_vars = 3000

; 上传
upload_max_filesize = 10M
post_max_size = 10M

; 会话
session.save_handler = files
session.save_path = "/var/lib/php/sessions"
session.gc_maxlifetime = 1440
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_strict_mode = 1

; OPcache
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.validate_timestamps = 1
opcache.revalidate_freq = 60

; 安全
expose_php = Off
allow_url_fopen = Off
allow_url_include = Off
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_multi_exec,parse_ini_file,show_source

5.2 OPcache 配置

; OPcache 配置
[opcache]
opcache.enable = 1
opcache.enable_cli = 0
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 1
opcache.revalidate_freq = 60
opcache.save_comments = 1
opcache.fast_shutdown = 1

; 生产环境优化
; opcache.validate_timestamps = 0
; opcache.revalidate_freq = 0
; 修改代码后需要重启 PHP-FPM

6. 常见 PHP 应用配置

6.1 WordPress

<VirtualHost *:80>
    ServerName wordpress.example.com
    DocumentRoot /var/www/wordpress
    
    <Directory "/var/www/wordpress">
        AllowOverride All
        Require all granted
        
        <FilesMatch "\.php$">
            SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
        </FilesMatch>
    </Directory>
    
    # WordPress 安全
    <Directory "/var/www/wordpress/wp-admin">
        <FilesMatch "\.php$">
            SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
        </FilesMatch>
    </Directory>
    
    # 保护 wp-config.php
    <Files "wp-config.php">
        Require all denied
    </Files>
    
    # 禁止目录浏览
    Options -Indexes
</VirtualHost>

6.2 Laravel

<VirtualHost *:80>
    ServerName laravel.example.com
    DocumentRoot /var/www/laravel/public
    
    <Directory "/var/www/laravel/public">
        AllowOverride All
        Require all granted
        
        <FilesMatch "\.php$">
            SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
        </FilesMatch>
    </Directory>
    
    # 重写规则(Laravel 需要)
    <IfModule mod_rewrite.c>
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^ index.php [L]
    </IfModule>
</VirtualHost>

6.3 phpMyAdmin

<VirtualHost *:80>
    ServerName pma.example.com
    DocumentRoot /usr/share/phpmyadmin
    
    <Directory "/usr/share/phpmyadmin">
        AllowOverride All
        
        # IP 限制
        Require ip 192.168.1.0/24
        
        <FilesMatch "\.php$">
            SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost"
        </FilesMatch>
    </Directory>
    
    # HTTPS 重定向
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>

7. 安全配置

7.1 PHP 安全头

<IfModule mod_headers.c>
    # 禁止 PHP 文件执行(上传目录)
    <Directory "/var/www/html/uploads">
        php_flag engine off
        <FilesMatch "\.ph(p[3457]?|t|tml)$">
            Require all denied
        </FilesMatch>
    </Directory>
</IfModule>

7.2 open_basedir 限制

# 按站点限制 PHP 访问范围
<VirtualHost *:80>
    ServerName www.example.com
    php_admin_value open_basedir "/var/www/html:/tmp:/usr/share/php"
    php_admin_value upload_tmp_dir "/var/www/html/tmp"
</VirtualHost>

7.3 禁用危险函数

; php.ini
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_multi_exec,parse_ini_file,show_source,pcntl_exec,pcntl_fork

8. 性能对比

# 测试 mod_php vs PHP-FPM

# 使用 ab 测试
ab -n 1000 -c 50 http://localhost/info.php

# mod_php 结果(prefork MPM)
# Requests per second: ~500
# Time per request: ~100ms

# PHP-FPM 结果(event MPM)
# Requests per second: ~1500
# Time per request: ~33ms

# 监控内存使用
ps aux | grep php | awk '{sum+=$6; count++} END {print "PHP 进程内存: " sum/1024 " MB, 进程数: " count}'

9. 故障排除

9.1 常见错误

# 错误:502 Bad Gateway
# 原因:PHP-FPM 未运行或 socket 权限问题
sudo systemctl status php8.2-fpm
ls -la /run/php/php8.2-fpm.sock

# 错误:503 Service Unavailable
# 原因:PHP-FPM 进程池耗尽
# 解决:增加 pm.max_children

# 错误:File not found
# 原因:DocumentRoot 不正确
# 解决:检查 DocumentRoot 和文件路径

# 错误:Permission denied
# 原因:文件权限问题
# 解决:chown -R www-data:www-data /var/www/html

# 错误:No input file specified
# 原因:PHP-FPM 无法访问文件
# 解决:检查 open_basedir 和文件权限

9.2 调试命令

# 检查 PHP-FPM 状态
sudo systemctl status php8.2-fpm

# 检查 PHP-FPM 配置
php-fpm8.2 -t

# 检查 PHP 版本和模块
php -v
php -m

# 检查 PHP 配置
php --ini
php -i | grep "Loaded Configuration File"

# 测试 PHP-FPM 连接
SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET \
    cgi-fcgi -bind -connect /run/php/php8.2-fpm.sock

# 查看 PHP-FPM 进程
ps aux | grep php-fpm

# 查看 PHP 错误日志
tail -f /var/log/php/error.log
tail -f /var/log/php-fpm-slow.log

10. 注意事项

  1. MPM 选择:PHP-FPM 配合 event MPM 性能最佳
  2. Socket 权限:确保 Apache 用户可以访问 PHP-FPM socket
  3. 版本兼容:确保 PHP 版本与应用兼容
  4. OPcache:生产环境务必启用 OPcache
  5. 安全加固:限制 PHP 函数、设置 open_basedir

11. 扩展阅读

12. 总结

PHP 集成方式的选择直接影响性能和安全:

  • PHP-FPM:生产环境推荐,高性能、高安全
  • mod_php:简单但性能较差,适合开发环境
  • 多版本管理:灵活支持不同应用需求
  • 安全配置:限制函数、隔离目录、禁用危险功能

合理配置 PHP 集成是 Apache 运维的重要技能。