本文目录导读:

在PHP中编写路由重写规则主要有两种方式:服务器配置(Apache/Nginx)和 PHP路由器,下面分别详细说明:
服务器配置层(重写URL)
Apache服务器(.htaccess)
# 启用重写引擎
RewriteEngine On
# 如果不是真实存在的文件或目录,则重写到index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
# 或者更复杂的规则
RewriteRule ^article/([0-9]+)$ article.php?id=$1 [L]
RewriteRule ^page/([a-z]+)$ page.php?name=$1 [L]
Nginx服务器
server {
listen 80;
server_name yourdomain.com;
root /var/www/html;
index index.php;
# 将所有请求重写到index.php
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# 更具体的规则
location ~ ^/article/(\d+)$ {
rewrite ^/article/(\d+)$ /article.php?id=$1 last;
}
location ~ ^/page/([a-z]+)$ {
rewrite ^/page/([a-z]+)$ /page.php?name=$1 last;
}
# PHP处理
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
PHP后端路由处理
简单的前端控制器
<?php
// index.php - 前端控制器
// 获取请求的URL
$request_uri = $_SERVER['REQUEST_URI'];
$base_path = dirname($_SERVER['SCRIPT_NAME']);
$path = substr($request_uri, strlen($base_path));
// 移除查询字符串
if (strpos($path, '?') !== false) {
$path = substr($path, 0, strpos($path, '?'));
}
$path = trim($path, '/');
$segments = $path ? explode('/', $path) : [];
// 默认路由
$controller = 'HomeController';
$action = 'index';
// 解析路由
if (isset($segments[0]) && $segments[0] !== '') {
$controller = ucfirst($segments[0]) . 'Controller';
}
if (isset($segments[1])) {
$action = $segments[1];
}
// 调用对应的控制器和方法
$controller_file = __DIR__ . '/controllers/' . $controller . '.php';
if (file_exists($controller_file)) {
require_once $controller_file;
$controller_instance = new $controller();
if (method_exists($controller_instance, $action)) {
$params = array_slice($segments, 2);
call_user_func_array([$controller_instance, $action], $params);
} else {
die('404 Not Found');
}
} else {
die('404 Not Found');
}
?>
高级路由类
<?php
// Router.php
class Router {
private $routes = [];
private $base_path = '';
public function __construct($base_path = '') {
$this->base_path = $base_path;
$this->parseRequest();
}
// 添加GET路由
public function get($route, $callback) {
$this->addRoute('GET', $route, $callback);
}
// 添加POST路由
public function post($route, $callback) {
$this->addRoute('POST', $route, $callback);
}
private function addRoute($method, $route, $callback) {
$this->routes[$method][$route] = $callback;
}
private function parseRequest() {
$uri = $_SERVER['REQUEST_URI'];
$base_path = $this->base_path;
if (strpos($uri, $base_path) === 0) {
$uri = substr($uri, strlen($base_path));
}
$uri = trim($uri, '/');
$this->path = $uri ?: '/';
$this->method = $_SERVER['REQUEST_METHOD'];
}
// 匹配路由
public function match() {
$path = rtrim($this->path, '/') ?: '/';
if (isset($this->routes[$this->method][$path])) {
$this->call($this->routes[$this->method][$path], []);
return true;
}
// 正则匹配带参数的路由
foreach ($this->routes[$this->method] ?? [] as $route => $callback) {
$pattern = preg_replace('/\{(\w+)\}/', '(?P<\1>[^/]+)', $route);
$pattern = '@^' . $pattern . '$@';
if (preg_match($pattern, $path, $matches)) {
$params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
$this->call($callback, array_values($params));
return true;
}
}
return false;
}
private function call($callback, $params) {
if (is_callable($callback)) {
call_user_func_array($callback, $params);
} elseif (is_string($callback) && strpos($callback, '@') !== false) {
list($controller, $method) = explode('@', $callback);
require_once "controllers/{$controller}.php";
$obj = new $controller();
$obj->$method(...$params);
}
}
}
// 使用示例
// index.php
$router = new Router('/myapp');
$router->get('/', function() {
echo 'Home Page';
});
$router->get('/user/{id}', 'UserController@show');
$router->post('/user/create', 'UserController@create');
if (!$router->match()) {
header('HTTP/1.1 404 Not Found');
echo '404 Not Found';
}
?>
RESTful API路由示例
<?php
// api.php
class ApiRouter {
private $routes = [];
public function get($route, $callback) {
$this->add('GET', $route, $callback);
}
public function post($route, $callback) {
$this->add('POST', $route, $callback);
}
private function add($method, $route, $callback) {
$this->routes[] = [
'method' => $method,
'route' => $route,
'callback' => $callback
];
}
public function handle() {
$method = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
$uri = rtrim($uri, '/');
$uri = urldecode($uri);
foreach ($this->routes as $route) {
if ($route['method'] === $method) {
$pattern = $this->patternToRegex($route['route']);
if (preg_match($pattern, $uri, $matches)) {
$params = [];
foreach ($matches as $key => $value) {
if (!is_int($key)) {
$params[$key] = $value;
}
}
call_user_func_array($route['callback'], array_values($params));
return true;
}
}
}
return false;
}
private function patternToRegex($pattern) {
$pattern = preg_replace('/\//', '\/', $pattern);
$pattern = preg_replace('/\{(\w+)\}/', '(?P<$1>[^/]+)', $pattern);
return '/^' . $pattern . '$/';
}
}
// 使用
$api = new ApiRouter();
$api->get('/api/users', function() {
// 返回所有用户
echo json_encode(['users' => []]);
});
$api->get('/api/users/{id}', function($id) {
// 返回指定用户
echo json_encode(['user' => $id]);
});
$api->post('/api/users', function() {
$data = json_decode(file_get_contents('php://input'), true);
// 创建新用户
echo json_encode(['status' => 'created']);
});
if (!$api->handle()) {
header('HTTP/1.1 404 Not Found');
echo json_encode(['error' => 'Not Found']);
}
?>
URL重写的常见场景
伪静态页面
/article/123 → article.php?id=123
/category/tech → category.php?name=tech
/tag/php → tag.php?name=php
用户友好URL
/profile/john → user.php?username=john
/orders/2023/01 → orders.php?year=2023&month=01
分页URL
/products/page/2 → products.php?page=2
/news/page/3 → news.php?page=3
最佳实践建议
- 使用Composer配合成熟路由库:如 FastRoute、Slim Framework、Laravel 的 Router
- 保持路由规则简单:避免过于复杂的正则表达式
- 缓存编译后的路由:提高性能
- 使用绝对路径:避免相对路径带来的混乱
- 支持RESTful风格:让你的API更规范
选择哪种方式取决于你的项目规模和需求,对于简单项目,直接用服务器配置或简单PHP代码即可;对于大型项目,建议使用成熟框架或Composer库。