本文目录导读:

我来详细讲解一下 PHP 的动静分离方案。
什么是动静分离
动静分离是指将动态请求(PHP 处理)和静态请求(图片、CSS、JS 等)分开处理,让静态资源直接由高性能的 Web 服务器(如 Nginx)处理,动态请求才转发给 PHP-FPM。
核心架构
用户请求 → Nginx
├── 静态文件 (.css/.js/.jpg等) → 直接返回
└── 动态请求 (.php等) → 转发给 PHP-FPM → 返回
配置方案
Nginx 基础配置
server {
listen 80;
server_name example.com;
# 设置根目录
root /var/www/html;
index index.php index.html;
# 静态文件处理规则
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|eot|ttf)$ {
expires 30d; # 设置浏览器缓存
access_log off; # 静态资源不记录访问日志
add_header Cache-Control "public, no-transform";
try_files $uri =404;
}
# 动态 PHP 请求处理
location ~ \.php$ {
# 检查文件是否存在
try_files $uri =404;
# 转发给 PHP-FPM
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# 动态请求不缓存
add_header Cache-Control "no-cache, must-revalidate";
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
}
高级优化配置
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.php index.html;
# 1. 静态文件优化配置
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff2?|eot|ttf|webp)$ {
expires 30d;
access_log off;
log_not_found off;
# 开启 gzip 压缩
gzip on;
gzip_types text/css application/javascript image/svg+xml;
# 开启浏览器缓存
add_header Cache-Control "public, immutable";
# 优化图片访问
location ~* \.(jpg|jpeg|png|gif|webp)$ {
expires 90d;
add_header X-Content-Type-Options nosniff;
}
}
# 2. 特定目录直接返回静态文件
location ^~ /static/ {
alias /var/www/html/static/;
expires 180d;
access_log off;
add_header Cache-Control "public, immutable";
}
# 3. 动态 PHP 请求
location ~ \.php$ {
# 检查文件存在
try_files $uri =404;
# 动态请求不缓存
add_header Cache-Control "no-store, must-revalidate";
add_header X-Frame-Options "SAMEORIGIN";
# 转发到 PHP-FPM
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS on;
# 超时设置
fastcgi_connect_timeout 30;
fastcgi_send_timeout 60;
fastcgi_read_timeout 60;
}
# 4. 图片防盗链(可选)
location ~* \.(jpg|jpeg|png|gif|webp)$ {
valid_referers none blocked *.example.com example.com;
if ($invalid_referer) {
return 403;
}
}
}
分离存储方案
将静态资源放到独立域名或 CDN:
# 静态资源服务器配置
server {
listen 80;
server_name static.example.com;
root /data/static; # 独立的静态资源目录
location / {
expires max;
add_header Cache-Control "public, immutable";
access_log off;
# 开启目录列表(可选)
autoindex off;
}
}
动态分离的 PHP 代码实现
模板中使用绝对路径
<!-- 动态页面中引用静态资源 --> <img src="https://static.example.com/images/logo.png"> <link rel="stylesheet" href="https://static.example.com/css/style.css"> <script src="https://static.example.com/js/main.js"></script>
统一资源管理函数
<?php
class ResourceManager {
private static $staticDomain = 'https://static.example.com';
// 生成静态资源 URL
public static function asset($path) {
$file = $_SERVER['DOCUMENT_ROOT'] . $path;
// 添加版本号(基于文件修改时间)
$version = file_exists($file) ? filemtime($file) : date('Ymd');
return self::$staticDomain . $path . '?v=' . $version;
}
// 检查是否需要更新缓存
public static function getVersion($path) {
$file = $_SERVER['DOCUMENT_ROOT'] . $path;
return file_exists($file) ? filemtime($file) : time();
}
}
// 使用示例
echo '<link rel="stylesheet" href="' . ResourceManager::asset('/css/style.css') . '">';
上传文件分离
<?php
class UploadManager {
private $staticServer = 'static.example.com';
private $uploadDir = '/data/static/uploads/';
public function upload($file) {
$targetPath = $this->uploadDir . date('Y/m/d') . '/';
if (!is_dir($targetPath)) {
mkdir($targetPath, 0755, true);
}
$filename = uniqid() . '.' . pathinfo($file['name'], PATHINFO_EXTENSION);
if (move_uploaded_file($file['tmp_name'], $targetPath . $filename)) {
// 返回静态服务器 URL
return "https://{$this->staticServer}/uploads/" . date('Y/m/d') . "/" . $filename;
}
return false;
}
}
性能优化建议
Nginx 层优化
# 开启 sendfile 加速 sendfile on; tcp_nopush on; tcp_nodelay on; # 静态资源缓存配置 open_file_cache max=1000 inactive=5m; open_file_cache_valid 2m; open_file_cache_min_uses 1; open_file_cache_errors on;
浏览器缓存策略
# CSS/JS 缓存策略
location ~* \.(css|js)$ {
expires 7d;
add_header Cache-Control "public, must-revalidate";
}
# 图片缓存策略
location ~* \.(jpg|jpeg|png|gif)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
PHP-FPM 优化
; php-fpm.conf pm.max_children = 50 pm.start_servers = 10 pm.min_spare_servers = 10 pm.max_spare_servers = 30
注意事项
-
安全考虑:
- 防止直接访问PHP文件
- 对上传目录执行权限限制
- 防止路径遍历攻击
-
缓存更新:
- 使用版本号管理静态资源
- 部署时更新版本号
- 配合 CDN 时注意缓存刷新
-
日志记录:
- 静态资源不走访问日志(减少IO)
- 动态请求记录详细日志
- 使用日志切割防止磁盘满
-
调试建议:
# 查看 Nginx 配置是否正确 nginx -t
查看 PHP-FPM 是否运行
systemctl status php8.1-fpm
测试静态资源访问
curl -I https://static.example.com/css/style.css
测试动态页面
curl -I https://example.com/index.php
这样配置后,静态请求不会进入 PHP 处理,大幅提升网站性能,减少 PHP-FPM 压力。