PHP 集成
PHP 集成
PHP 是最常用的 Web 开发语言之一。Apache 提供了多种 PHP 集成方式。
1. 集成方式对比
| 方式 | 模块 | MPM | 性能 | 安全 | 推荐 |
|---|---|---|---|---|---|
| mod_php | libapache2-mod-php | prefork | 中 | 较低 | ❌ |
| PHP-FPM | proxy_fcgi | event/worker | 高 | 高 | ✅ |
| FastCGI | mod_fcgid | event/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. 注意事项
- MPM 选择:PHP-FPM 配合 event MPM 性能最佳
- Socket 权限:确保 Apache 用户可以访问 PHP-FPM socket
- 版本兼容:确保 PHP 版本与应用兼容
- OPcache:生产环境务必启用 OPcache
- 安全加固:限制 PHP 函数、设置 open_basedir
11. 扩展阅读
12. 总结
PHP 集成方式的选择直接影响性能和安全:
- PHP-FPM:生产环境推荐,高性能、高安全
- mod_php:简单但性能较差,适合开发环境
- 多版本管理:灵活支持不同应用需求
- 安全配置:限制函数、隔离目录、禁用危险功能
合理配置 PHP 集成是 Apache 运维的重要技能。