模拟 Apache mod_rewrite 路由

通过使用从 app.yaml 中引用的 PHP 脚本,您可以模拟基本的 Apache mod_rewrite 功能,该文件将依次加载所需的脚本。此示例将模拟要求变量 $_GET['q'] 包含请求路径的常见 PHP 模式。

mod_rewrite.php 简介

要启用 mod_rewrite 功能,您的应用需要包含将针对应用的所有请求调用的 mod_rewrite.php 脚本,以便执行请求路由。如注释中所述,脚本将检查是否存在根级 PHP 脚本,并在调用这些脚本的同时将 $_SERVER['REQUEST_URI'] 路径部分放入 $_GET['q'] 变量。

<?php
/**
 * @file
 * Provide basic mod_rewrite like functionality.
 *
 * Pass through requests for root php files and forward all other requests to
 * index.php with $_GET['q'] equal to path. The following are examples that
 * demonstrate how a request using mod_rewrite.php will appear to a PHP script.
 *
 * - /install.php: install.php
 * - /update.php?op=info: update.php?op=info
 * - /foo/bar: index.php?q=/foo/bar
 * - /: index.php?q=/
 */

$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

// Provide mod_rewrite like functionality. If a php file in the root directory
// is explicitly requested then load the file, otherwise load index.php and
// set get variable 'q' to $_SERVER['REQUEST_URI'].
if (dirname($path) == '/' && pathinfo($path, PATHINFO_EXTENSION) == 'php') {
  $file = pathinfo($path, PATHINFO_BASENAME);
}
else {
  $file = 'index.php';

  // Provide mod_rewrite like functionality by using the path which excludes
  // any other part of the request query (ie. ignores ?foo=bar).
  $_GET['q'] = $path;
}

// Override the script name to simulate the behavior without mod_rewrite.php.
// Ensure that $_SERVER['SCRIPT_NAME'] always begins with a / to be consistent
// with HTTP request and the value that is normally provided.
$_SERVER['SCRIPT_NAME'] = '/' . $file;
require $file;

示例应用

下面显示了一个非常简单的应用,其编写目的在于获取 $_GET['q']

app.yaml

从该 app.yaml 文件中可以看出,此应用将提供两个根级 PHP 脚本,并从名为 downloads 的目录中传送静态文件。

application: mod_rewrite_simulator
version: 1
runtime: php55
api_version: 1

handlers:
# Example of handler which should be placed above the catch-all handler.
- url: /downloads
  static_dir: downloads

# Catch all unhandled requests and pass to mod_rewrite.php which will simulate
# mod_rewrite by forwarding the requests to index.php?q=... (or other root-level
# PHP file if specified in incoming URL.
- url: /.*
  script: mod_rewrite.php

index.php

index.php 是路由器样式的 index.php,它读取 $_GET['q'] 来确定请求路径。

<?php

if ($_GET['q'] == '/help') {
  echo 'This is some help text.';
  exit;
}

echo 'Welcome to the site!';

other.php

以下是可以直接调用的根级脚本的示例。许多 PHP 框架都有 install.phpupdate.php 等脚本实现类似功能。

<?php

echo 'Welcome to the other site.';

示例请求

参考上方的示例应用,以下请求将作如下处理。

  • / 使用 $_GET['q'] = '/' 解析为 index.php
  • /help 使用 $_GET['q'] = '/help' 解析为 index.php
  • /other.php 使用 $_GET['q'] = null 解析为 other.php
  • /downloads/foo_17.png 解析为 downloads/foo_17.png

避免使用 mod_rewrite.php

许多 PHP 框架不再依赖于 $_GET['q']。这些框架改用 $_SERVER['REQUEST_URI'],该语法无需借助 mod_rewrite 发挥作用。因此后者是 App Engine 上的首选方法。

mod_rewrite.php 中,利用 REQUEST_URI 的简单方法如下:

<?php

$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

if ($path == '/help') {
  echo 'This is some help text.';
  exit;
}

echo 'Welcome to the site!';