PHP路由重写规则怎么写

wen PHP项目 1

本文目录导读:

PHP路由重写规则怎么写

  1. 服务器配置层(重写URL)
  2. PHP后端路由处理
  3. URL重写的常见场景
  4. 最佳实践建议

在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

最佳实践建议

  1. 使用Composer配合成熟路由库:如 FastRoute、Slim Framework、Laravel 的 Router
  2. 保持路由规则简单:避免过于复杂的正则表达式
  3. 缓存编译后的路由:提高性能
  4. 使用绝对路径:避免相对路径带来的混乱
  5. 支持RESTful风格:让你的API更规范

选择哪种方式取决于你的项目规模和需求,对于简单项目,直接用服务器配置或简单PHP代码即可;对于大型项目,建议使用成熟框架或Composer库。

抱歉,评论功能暂时关闭!